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 76773 : OGRLayer::OGRLayer()
35 76773 : : 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 153546 : m_poAttrIndex(nullptr), m_nRefCount(0), m_nFeaturesRead(0)
40 : {
41 76773 : }
42 :
43 : /************************************************************************/
44 : /* ~OGRLayer() */
45 : /************************************************************************/
46 :
47 76753 : OGRLayer::~OGRLayer()
48 :
49 : {
50 76753 : if (m_poStyleTable)
51 : {
52 11 : delete m_poStyleTable;
53 11 : m_poStyleTable = nullptr;
54 : }
55 :
56 76753 : if (m_poAttrIndex != nullptr)
57 : {
58 174 : delete m_poAttrIndex;
59 174 : m_poAttrIndex = nullptr;
60 : }
61 :
62 76753 : if (m_poAttrQuery != nullptr)
63 : {
64 656 : delete m_poAttrQuery;
65 656 : m_poAttrQuery = nullptr;
66 : }
67 :
68 76753 : CPLFree(m_pszAttrQueryString);
69 :
70 76753 : if (m_poFilterGeom)
71 : {
72 1079 : delete m_poFilterGeom;
73 1079 : m_poFilterGeom = nullptr;
74 : }
75 :
76 76753 : if (m_pPreparedFilterGeom != nullptr)
77 : {
78 1079 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
79 1079 : m_pPreparedFilterGeom = nullptr;
80 : }
81 :
82 76753 : if (m_poSharedArrowArrayStreamPrivateData != nullptr)
83 : {
84 758 : m_poSharedArrowArrayStreamPrivateData->m_poLayer = nullptr;
85 : }
86 76753 : }
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 14631 : GIntBig OGRLayer::GetFeatureCount(int bForce)
205 :
206 : {
207 14631 : if (!bForce)
208 1 : return -1;
209 :
210 14630 : GIntBig nFeatureCount = 0;
211 57305 : for (auto &&poFeature : *this)
212 : {
213 42675 : CPL_IGNORE_RET_VAL(poFeature.get());
214 42675 : nFeatureCount++;
215 : }
216 14630 : ResetReading();
217 :
218 14630 : 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 37442 : GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
250 :
251 : {
252 37442 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
253 :
254 : #ifdef OGRAPISPY_ENABLED
255 37442 : if (bOGRAPISpyEnabled)
256 2 : OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
257 : #endif
258 :
259 37442 : 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 15464 : OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, bool bForce)
295 : {
296 15464 : 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 17831 : OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
330 : {
331 17831 : psExtent->MinX = 0.0;
332 17831 : psExtent->MaxX = 0.0;
333 17831 : psExtent->MinY = 0.0;
334 17831 : 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 34782 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
341 16951 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
342 : {
343 880 : if (iGeomField != 0)
344 : {
345 710 : CPLError(CE_Failure, CPLE_AppDefined,
346 : "Invalid geometry field index : %d", iGeomField);
347 : }
348 880 : return OGRERR_FAILURE;
349 : }
350 :
351 16951 : 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 543 : 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 543 : 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 541 : OGREnvelope oEnv;
391 541 : bool bExtentSet = false;
392 :
393 10107 : for (auto &&poFeature : *this)
394 : {
395 9566 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
396 9566 : if (poGeom == nullptr || poGeom->IsEmpty())
397 : {
398 : /* Do nothing */
399 : }
400 9263 : else if (!bExtentSet)
401 : {
402 486 : poGeom->getEnvelope(psExtent);
403 972 : if (!(std::isnan(psExtent->MinX) || std::isnan(psExtent->MinY) ||
404 486 : std::isnan(psExtent->MaxX) || std::isnan(psExtent->MaxY)))
405 : {
406 486 : bExtentSet = true;
407 : }
408 : }
409 : else
410 : {
411 8777 : poGeom->getEnvelope(&oEnv);
412 8777 : if (oEnv.MinX < psExtent->MinX)
413 345 : psExtent->MinX = oEnv.MinX;
414 8777 : if (oEnv.MinY < psExtent->MinY)
415 389 : psExtent->MinY = oEnv.MinY;
416 8777 : if (oEnv.MaxX > psExtent->MaxX)
417 960 : psExtent->MaxX = oEnv.MaxX;
418 8777 : if (oEnv.MaxY > psExtent->MaxY)
419 949 : psExtent->MaxY = oEnv.MaxY;
420 : }
421 : }
422 541 : ResetReading();
423 :
424 541 : 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 43 : OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
462 :
463 : {
464 43 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
465 :
466 : #ifdef OGRAPISPY_ENABLED
467 43 : if (bOGRAPISpyEnabled)
468 0 : OGRAPISpy_L_GetExtent(hLayer, bForce);
469 : #endif
470 :
471 43 : return OGRLayer::FromHandle(hLayer)->GetExtent(0, psExtent,
472 43 : 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 17111 : OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
753 :
754 : {
755 17111 : CPLFree(m_pszAttrQueryString);
756 17111 : m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
757 :
758 : /* -------------------------------------------------------------------- */
759 : /* Are we just clearing any existing query? */
760 : /* -------------------------------------------------------------------- */
761 17111 : if (pszQuery == nullptr || strlen(pszQuery) == 0)
762 : {
763 11377 : if (m_poAttrQuery)
764 : {
765 3367 : delete m_poAttrQuery;
766 3367 : m_poAttrQuery = nullptr;
767 3367 : ResetReading();
768 : }
769 11377 : return OGRERR_NONE;
770 : }
771 :
772 : /* -------------------------------------------------------------------- */
773 : /* Or are we installing a new query? */
774 : /* -------------------------------------------------------------------- */
775 : OGRErr eErr;
776 :
777 5734 : if (!m_poAttrQuery)
778 4081 : m_poAttrQuery = new OGRFeatureQuery();
779 :
780 5734 : eErr = m_poAttrQuery->Compile(this, pszQuery);
781 5734 : if (eErr != OGRERR_NONE)
782 : {
783 3 : delete m_poAttrQuery;
784 3 : m_poAttrQuery = nullptr;
785 : }
786 :
787 5734 : ResetReading();
788 :
789 5734 : return eErr;
790 : }
791 :
792 : /************************************************************************/
793 : /* ContainGeomSpecialField() */
794 : /************************************************************************/
795 :
796 307 : static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
797 : {
798 307 : if (expr->eNodeType == SNT_COLUMN)
799 : {
800 68 : if (expr->table_index == 0 && expr->field_index != -1)
801 : {
802 68 : int nSpecialFieldIdx = expr->field_index - nLayerFieldCount;
803 68 : return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
804 136 : nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
805 68 : nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
806 : }
807 : }
808 239 : else if (expr->eNodeType == SNT_OPERATION)
809 : {
810 360 : for (int i = 0; i < expr->nSubExprCount; i++)
811 : {
812 236 : if (ContainGeomSpecialField(expr->papoSubExpr[i], nLayerFieldCount))
813 0 : return TRUE;
814 : }
815 : }
816 239 : return FALSE;
817 : }
818 :
819 : /************************************************************************/
820 : /* AttributeFilterEvaluationNeedsGeometry() */
821 : /************************************************************************/
822 :
823 : //! @cond Doxygen_Suppress
824 71 : int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
825 : {
826 71 : if (!m_poAttrQuery)
827 0 : return FALSE;
828 :
829 : swq_expr_node *expr =
830 71 : static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
831 71 : int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
832 :
833 71 : return ContainGeomSpecialField(expr, nLayerFieldCount);
834 : }
835 :
836 : //! @endcond
837 :
838 : /************************************************************************/
839 : /* OGR_L_SetAttributeFilter() */
840 : /************************************************************************/
841 :
842 : /**
843 : \brief Set a new attribute query.
844 :
845 : This function sets the attribute query string to be used when
846 : fetching features via the OGR_L_GetNextFeature() function.
847 : Only features for which the query evaluates as true will be returned.
848 :
849 : The query string should be in the format of an SQL WHERE clause. For
850 : instance "population > 1000000 and population < 5000000" where population
851 : is an attribute in the layer. The query format is normally a SQL WHERE clause
852 : as described in the
853 : <a href="https://gdal.org/user/ogr_sql_dialect.html#where">"WHERE"</a> section
854 : of the OGR SQL dialect documentation.
855 : In some cases (RDBMS backed drivers, SQLite, GeoPackage) the native
856 : capabilities of the database may be used to to interpret the WHERE clause, in
857 : which case the capabilities will be broader than those of OGR SQL.
858 :
859 : Note that installing a query string will generally result in resetting
860 : the current reading position (ala OGR_L_ResetReading()).
861 :
862 : This function is the same as the C++ method OGRLayer::SetAttributeFilter().
863 :
864 : @param hLayer handle to the layer on which attribute query will be executed.
865 : @param pszQuery query in restricted SQL WHERE format, or NULL to clear the
866 : current query.
867 :
868 : @return OGRERR_NONE if successfully installed, or an error code if the
869 : query expression is in error, or some other failure occurs.
870 : */
871 :
872 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 1085 : OGRFeature *OGRLayer::GetFeature(GIntBig nFID)
943 :
944 : {
945 : /* Save old attribute and spatial filters */
946 : char *pszOldFilter =
947 1085 : m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
948 : OGRGeometry *poOldFilterGeom =
949 1085 : (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr;
950 1085 : int iOldGeomFieldFilter = m_iGeomFieldFilter;
951 : /* Unset filters */
952 1085 : SetAttributeFilter(nullptr);
953 1085 : SetSpatialFilter(0, nullptr);
954 :
955 1085 : OGRFeatureUniquePtr poFeature;
956 14856 : for (auto &&poFeatureIter : *this)
957 : {
958 13771 : if (poFeatureIter->GetFID() == nFID)
959 : {
960 713 : poFeature.swap(poFeatureIter);
961 713 : break;
962 : }
963 : }
964 :
965 : /* Restore filters */
966 1085 : SetAttributeFilter(pszOldFilter);
967 1085 : CPLFree(pszOldFilter);
968 1085 : SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
969 1085 : delete poOldFilterGeom;
970 :
971 2170 : 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 2618 : OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
1010 :
1011 : {
1012 2618 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
1013 :
1014 : #ifdef OGRAPISPY_ENABLED
1015 2618 : if (bOGRAPISpyEnabled)
1016 2 : OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
1017 : #endif
1018 :
1019 2618 : return OGRFeature::ToHandle(
1020 5236 : 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 1204 : OGRErr OGRLayer::SetNextByIndex(GIntBig nIndex)
1058 :
1059 : {
1060 1204 : if (nIndex < 0)
1061 249 : nIndex = GINTBIG_MAX;
1062 :
1063 1204 : ResetReading();
1064 :
1065 133273 : while (nIndex-- > 0)
1066 : {
1067 132567 : auto poFeature = std::unique_ptr<OGRFeature>(GetNextFeature());
1068 132567 : if (poFeature == nullptr)
1069 498 : return OGRERR_NON_EXISTING_FEATURE;
1070 : }
1071 :
1072 706 : 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 94997 : OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
1200 :
1201 : {
1202 94997 : VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
1203 :
1204 : #ifdef OGRAPISPY_ENABLED
1205 94997 : if (bOGRAPISpyEnabled)
1206 8 : OGRAPISpy_L_GetNextFeature(hLayer);
1207 : #endif
1208 :
1209 94997 : return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
1210 : }
1211 :
1212 : /************************************************************************/
1213 : /* ConvertGeomsIfNecessary() */
1214 : /************************************************************************/
1215 :
1216 991880 : void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
1217 : {
1218 991880 : if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
1219 : {
1220 : // One time initialization
1221 10639 : m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
1222 10639 : m_poPrivate->m_bSupportsCurve =
1223 10639 : CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
1224 10639 : m_poPrivate->m_bSupportsM =
1225 10639 : CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
1226 10639 : 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 1891590 : if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
1247 899707 : m_poPrivate->m_bApplyGeomSetPrecision)
1248 : {
1249 92175 : const auto poFeatureDefn = GetLayerDefn();
1250 92175 : const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
1251 182043 : for (int i = 0; i < nGeomFieldCount; i++)
1252 : {
1253 89868 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
1254 89868 : if (poGeom)
1255 : {
1256 106279 : if (!m_poPrivate->m_bSupportsM &&
1257 19388 : OGR_GT_HasM(poGeom->getGeometryType()))
1258 : {
1259 5 : poGeom->setMeasured(FALSE);
1260 : }
1261 :
1262 173584 : if (!m_poPrivate->m_bSupportsCurve &&
1263 86693 : OGR_GT_IsNonLinear(poGeom->getGeometryType()))
1264 : {
1265 : OGRwkbGeometryType eTargetType =
1266 31 : OGR_GT_GetLinear(poGeom->getGeometryType());
1267 : auto poGeomUniquePtr = OGRGeometryFactory::forceTo(
1268 31 : std::unique_ptr<OGRGeometry>(
1269 : poFeature->StealGeometry(i)),
1270 31 : eTargetType);
1271 31 : poFeature->SetGeomField(i, std::move(poGeomUniquePtr));
1272 31 : poGeom = poFeature->GetGeomFieldRef(i);
1273 : }
1274 :
1275 86891 : 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 991880 : }
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 3179 : OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
1342 :
1343 : {
1344 3179 : ConvertGeomsIfNecessary(poFeature);
1345 3179 : 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 199 : OGRErr OGRLayer::ISetFeature(OGRFeature *poFeature)
1370 :
1371 : {
1372 : (void)poFeature;
1373 199 : 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 534 : OGRErr OGRLayer::SetFeature(std::unique_ptr<OGRFeature> poFeature)
1475 :
1476 : {
1477 534 : ConvertGeomsIfNecessary(poFeature.get());
1478 534 : 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 667361 : OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
1540 :
1541 : {
1542 667361 : ConvertGeomsIfNecessary(poFeature);
1543 667361 : 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 299764 : OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1602 :
1603 : {
1604 299764 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1605 299764 : VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1606 :
1607 : #ifdef OGRAPISPY_ENABLED
1608 299764 : if (bOGRAPISpyEnabled)
1609 5 : OGRAPISpy_L_CreateFeature(hLayer, hFeat);
1610 : #endif
1611 :
1612 299764 : return OGRLayer::FromHandle(hLayer)->CreateFeature(
1613 299764 : 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 320698 : OGRErr OGRLayer::CreateFeature(std::unique_ptr<OGRFeature> poFeature,
1645 : GIntBig *pnFID)
1646 :
1647 : {
1648 320698 : ConvertGeomsIfNecessary(poFeature.get());
1649 320698 : 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.");
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 78252 : OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
2125 :
2126 : {
2127 78252 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
2128 78252 : VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
2129 :
2130 : #ifdef OGRAPISPY_ENABLED
2131 78252 : if (bOGRAPISpyEnabled)
2132 6 : OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
2133 : #endif
2134 :
2135 156504 : return OGRLayer::FromHandle(hLayer)->CreateField(
2136 78252 : 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.");
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.");
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.");
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.");
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.");
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 147 : OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
2745 : int bApproxOK)
2746 :
2747 : {
2748 147 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
2749 147 : VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
2750 :
2751 : #ifdef OGRAPISPY_ENABLED
2752 147 : if (bOGRAPISpyEnabled)
2753 2 : OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
2754 : #endif
2755 :
2756 294 : return OGRLayer::FromHandle(hLayer)->CreateGeomField(
2757 147 : 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 889 : OGRErr OGRLayer::StartTransaction()
2782 :
2783 : {
2784 889 : 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 839 : OGRErr OGRLayer::CommitTransaction()
2841 :
2842 : {
2843 839 : 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 135030 : OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
3007 :
3008 : {
3009 135030 : VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
3010 :
3011 : #ifdef OGRAPISPY_ENABLED
3012 135030 : if (bOGRAPISpyEnabled)
3013 15 : OGRAPISpy_L_GetLayerDefn(hLayer);
3014 : #endif
3015 :
3016 135030 : return OGRFeatureDefn::ToHandle(
3017 135030 : 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 83 : int OGRLayer::FindFieldIndex(const char *pszFieldName,
3074 : CPL_UNUSED int bExactMatch)
3075 : {
3076 83 : 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 441062 : const OGRSpatialReference *OGRLayer::GetSpatialRef() const
3104 : {
3105 441062 : const auto poLayerDefn = GetLayerDefn();
3106 441062 : if (poLayerDefn->GetGeomFieldCount() > 0)
3107 : return const_cast<OGRSpatialReference *>(
3108 440459 : poLayerDefn->GetGeomFieldDefn(0)->GetSpatialRef());
3109 : else
3110 603 : 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 1146 : OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
3130 :
3131 : {
3132 1146 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
3133 :
3134 : #ifdef OGRAPISPY_ENABLED
3135 1146 : if (bOGRAPISpyEnabled)
3136 2 : OGRAPISpy_L_GetSpatialRef(hLayer);
3137 : #endif
3138 :
3139 1146 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
3140 1146 : 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 482 : OGRGeometry *OGRLayer::GetSpatialFilter()
3382 :
3383 : {
3384 482 : 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 53971 : bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
3423 : int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
3424 : {
3425 53971 : 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 107657 : else if (iGeomField < 0 ||
3433 53686 : iGeomField >= GetLayerDefn()->GetGeomFieldCount())
3434 : {
3435 663 : if (iGeomField == 0)
3436 : {
3437 91 : 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 572 : CPLError(CE_Failure, CPLE_AppDefined,
3447 : "Cannot set spatial filter on non-existing geometry field "
3448 : "of index %d.",
3449 : iGeomField);
3450 : }
3451 663 : return false;
3452 : }
3453 53308 : 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 6947 : OGRErr OGRLayer::SetSpatialFilter(const OGRGeometry *poFilter)
3494 :
3495 : {
3496 6947 : 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 66506 : OGRErr OGRLayer::SetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
3534 :
3535 : {
3536 66506 : if (iGeomField == 0)
3537 : {
3538 117875 : if (poFilter &&
3539 52669 : !ValidateGeometryFieldIndexForSetSpatialFilter(0, poFilter))
3540 : {
3541 91 : return OGRERR_FAILURE;
3542 : }
3543 : }
3544 : else
3545 : {
3546 1300 : if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField,
3547 : poFilter))
3548 : {
3549 572 : return OGRERR_FAILURE;
3550 : }
3551 : }
3552 :
3553 65843 : 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 37821 : OGRErr OGRLayer::ISetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
3580 :
3581 : {
3582 37821 : m_iGeomFieldFilter = iGeomField;
3583 37821 : if (InstallFilter(poFilter))
3584 29311 : ResetReading();
3585 37821 : 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 48335 : OGRErr OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY,
3726 : double dfMaxX, double dfMaxY)
3727 :
3728 : {
3729 48335 : 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 48375 : OGRErr OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
3760 : double dfMinY, double dfMaxX,
3761 : double dfMaxY)
3762 :
3763 : {
3764 96750 : auto poRing = std::make_unique<OGRLinearRing>();
3765 96750 : OGRPolygon oPoly;
3766 :
3767 48375 : poRing->addPoint(dfMinX, dfMinY);
3768 48375 : poRing->addPoint(dfMinX, dfMaxY);
3769 48375 : poRing->addPoint(dfMaxX, dfMaxY);
3770 48375 : poRing->addPoint(dfMaxX, dfMinY);
3771 48375 : poRing->addPoint(dfMinX, dfMinY);
3772 :
3773 48375 : oPoly.addRing(std::move(poRing));
3774 :
3775 96750 : 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 64803 : int OGRLayer::InstallFilter(const OGRGeometry *poFilter)
3889 :
3890 : {
3891 64803 : if (m_poFilterGeom == poFilter)
3892 9936 : return FALSE;
3893 :
3894 : /* -------------------------------------------------------------------- */
3895 : /* Replace the existing filter. */
3896 : /* -------------------------------------------------------------------- */
3897 54867 : if (m_poFilterGeom != nullptr)
3898 : {
3899 51603 : delete m_poFilterGeom;
3900 51603 : m_poFilterGeom = nullptr;
3901 : }
3902 :
3903 54867 : if (m_pPreparedFilterGeom != nullptr)
3904 : {
3905 51603 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
3906 51603 : m_pPreparedFilterGeom = nullptr;
3907 : }
3908 :
3909 54867 : if (poFilter != nullptr)
3910 52682 : m_poFilterGeom = poFilter->clone();
3911 :
3912 54867 : m_bFilterIsEnvelope = FALSE;
3913 :
3914 54867 : if (m_poFilterGeom == nullptr)
3915 2185 : return TRUE;
3916 :
3917 52682 : m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
3918 :
3919 : /* Compile geometry filter as a prepared geometry */
3920 52682 : m_pPreparedFilterGeom =
3921 52682 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
3922 :
3923 52682 : m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
3924 :
3925 52682 : return TRUE;
3926 : }
3927 :
3928 : //! @endcond
3929 :
3930 : /************************************************************************/
3931 : /* DoesGeometryHavePointInEnvelope() */
3932 : /************************************************************************/
3933 :
3934 5989 : static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
3935 : const OGREnvelope &sEnvelope)
3936 : {
3937 5989 : const OGRLineString *poLS = nullptr;
3938 :
3939 5989 : 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 4738 : case wkbPolygon:
3955 : {
3956 4738 : const OGRPolygon *poPoly = poGeometry->toPolygon();
3957 4738 : poLS = poPoly->getExteriorRing();
3958 4738 : 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 5173 : if (poLS != nullptr)
3979 : {
3980 5173 : const int nNumPoints = poLS->getNumPoints();
3981 59770 : for (int i = 0; i < nNumPoints; i++)
3982 : {
3983 58646 : const double x = poLS->getX(i);
3984 58646 : const double y = poLS->getY(i);
3985 58646 : if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
3986 24295 : x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
3987 : {
3988 4049 : return true;
3989 : }
3990 : }
3991 : }
3992 :
3993 1124 : 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 444832 : 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 444832 : if (m_poFilterGeom == nullptr)
4014 376 : return TRUE;
4015 :
4016 444456 : 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 444153 : OGREnvelope sGeomEnv;
4025 :
4026 444153 : poGeometry->getEnvelope(&sGeomEnv);
4027 :
4028 444153 : if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
4029 296426 : sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
4030 231401 : m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
4031 133884 : m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
4032 326306 : 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 117847 : if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
4040 112088 : sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
4041 110660 : sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
4042 109743 : sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
4043 : {
4044 109367 : 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 8480 : if (m_bFilterIsEnvelope)
4052 : {
4053 5304 : if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
4054 4059 : 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 4421 : if (OGRGeometryFactory::haveGEOS())
4064 : {
4065 : // CPLDebug("OGRLayer", "GEOS intersection");
4066 4421 : if (m_pPreparedFilterGeom != nullptr)
4067 4421 : return OGRPreparedGeometryIntersects(
4068 : m_pPreparedFilterGeom,
4069 : OGRGeometry::ToHandle(
4070 4421 : 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 : bool bRet =
4089 460 : FilterWKBGeometry(pabyWKB, nWKBSize, bEnvelopeAlreadySet, sEnvelope,
4090 230 : m_poFilterGeom, CPL_TO_BOOL(m_bFilterIsEnvelope),
4091 230 : m_sFilterEnvelope, pPreparedFilterGeom);
4092 230 : const_cast<OGRLayer *>(this)->m_pPreparedFilterGeom = pPreparedFilterGeom;
4093 230 : return bRet;
4094 : }
4095 :
4096 : /* static */
4097 334 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
4098 : bool bEnvelopeAlreadySet,
4099 : OGREnvelope &sEnvelope,
4100 : const OGRGeometry *poFilterGeom,
4101 : bool bFilterIsEnvelope,
4102 : const OGREnvelope &sFilterEnvelope,
4103 : OGRPreparedGeometry *&pPreparedFilterGeom)
4104 : {
4105 334 : if (!poFilterGeom)
4106 0 : return true;
4107 :
4108 637 : if ((bEnvelopeAlreadySet ||
4109 668 : OGRWKBGetBoundingBox(pabyWKB, nWKBSize, sEnvelope)) &&
4110 334 : sFilterEnvelope.Intersects(sEnvelope))
4111 : {
4112 161 : if (bFilterIsEnvelope && sFilterEnvelope.Contains(sEnvelope))
4113 : {
4114 98 : return true;
4115 : }
4116 : else
4117 : {
4118 126 : if (bFilterIsEnvelope &&
4119 63 : OGRWKBIntersectsPessimistic(pabyWKB, nWKBSize, sFilterEnvelope))
4120 : {
4121 51 : return true;
4122 : }
4123 12 : else if (OGRGeometryFactory::haveGEOS())
4124 : {
4125 12 : OGRGeometry *poGeom = nullptr;
4126 12 : int ret = FALSE;
4127 12 : if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeom,
4128 12 : nWKBSize) == OGRERR_NONE)
4129 : {
4130 12 : if (!pPreparedFilterGeom)
4131 : {
4132 0 : pPreparedFilterGeom =
4133 0 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(
4134 : const_cast<OGRGeometry *>(poFilterGeom)));
4135 : }
4136 12 : if (pPreparedFilterGeom)
4137 12 : ret = OGRPreparedGeometryIntersects(
4138 : pPreparedFilterGeom,
4139 : OGRGeometry::ToHandle(
4140 : const_cast<OGRGeometry *>(poGeom)));
4141 : else
4142 0 : ret = poFilterGeom->Intersects(poGeom);
4143 : }
4144 12 : delete poGeom;
4145 12 : return CPL_TO_BOOL(ret);
4146 : }
4147 : else
4148 : {
4149 : // Assume intersection
4150 0 : return true;
4151 : }
4152 : }
4153 : }
4154 :
4155 173 : return false;
4156 : }
4157 :
4158 : /************************************************************************/
4159 : /* PrepareStartTransaction() */
4160 : /************************************************************************/
4161 :
4162 3060 : void OGRLayer::PrepareStartTransaction()
4163 : {
4164 3060 : m_apoFieldDefnChanges.clear();
4165 3060 : m_apoGeomFieldDefnChanges.clear();
4166 3060 : }
4167 :
4168 : /************************************************************************/
4169 : /* FinishRollbackTransaction() */
4170 : /************************************************************************/
4171 :
4172 173 : void OGRLayer::FinishRollbackTransaction(const std::string &osSavepointName)
4173 : {
4174 :
4175 : // Deleted fields can be safely removed from the storage after being restored.
4176 346 : std::vector<int> toBeRemoved;
4177 :
4178 173 : bool bSavepointFound = false;
4179 :
4180 : // Loop through all changed fields and reset them to their previous state.
4181 376 : for (int i = static_cast<int>(m_apoFieldDefnChanges.size()) - 1; i >= 0;
4182 : i--)
4183 : {
4184 203 : auto &oFieldChange = m_apoFieldDefnChanges[i];
4185 :
4186 203 : if (!osSavepointName.empty())
4187 : {
4188 172 : if (oFieldChange.osSavepointName == osSavepointName)
4189 : {
4190 60 : bSavepointFound = true;
4191 : }
4192 112 : else if (bSavepointFound)
4193 : {
4194 56 : continue;
4195 : }
4196 : }
4197 :
4198 147 : CPLAssert(oFieldChange.poFieldDefn);
4199 147 : const char *pszName = oFieldChange.poFieldDefn->GetNameRef();
4200 147 : const int iField = oFieldChange.iField;
4201 147 : if (iField >= 0)
4202 : {
4203 147 : switch (oFieldChange.eChangeType)
4204 : {
4205 128 : case FieldChangeType::DELETE_FIELD:
4206 : {
4207 : // Transfer ownership of the field to the layer
4208 256 : whileUnsealing(GetLayerDefn())
4209 128 : ->AddFieldDefn(std::move(oFieldChange.poFieldDefn));
4210 :
4211 : // Now move the field to the right place
4212 : // from the last position to its original position
4213 128 : const int iFieldCount = GetLayerDefn()->GetFieldCount();
4214 128 : CPLAssert(iFieldCount > 0);
4215 128 : CPLAssert(iFieldCount > iField);
4216 256 : std::vector<int> anOrder(iFieldCount);
4217 204 : for (int j = 0; j < iField; j++)
4218 : {
4219 76 : anOrder[j] = j;
4220 : }
4221 248 : for (int j = iField + 1; j < iFieldCount; j++)
4222 : {
4223 120 : anOrder[j] = j - 1;
4224 : }
4225 128 : anOrder[iField] = iFieldCount - 1;
4226 256 : if (OGRERR_NONE == whileUnsealing(GetLayerDefn())
4227 128 : ->ReorderFieldDefns(anOrder.data()))
4228 : {
4229 128 : toBeRemoved.push_back(i);
4230 : }
4231 : else
4232 : {
4233 0 : CPLError(CE_Failure, CPLE_AppDefined,
4234 : "Failed to restore deleted field %s", pszName);
4235 : }
4236 128 : break;
4237 : }
4238 8 : case FieldChangeType::ALTER_FIELD:
4239 : {
4240 : OGRFieldDefn *poFieldDefn =
4241 8 : GetLayerDefn()->GetFieldDefn(iField);
4242 8 : if (poFieldDefn)
4243 : {
4244 8 : *poFieldDefn = *oFieldChange.poFieldDefn;
4245 8 : toBeRemoved.push_back(i);
4246 : }
4247 : else
4248 : {
4249 0 : CPLError(CE_Failure, CPLE_AppDefined,
4250 : "Failed to restore altered field %s", pszName);
4251 : }
4252 8 : break;
4253 : }
4254 11 : case FieldChangeType::ADD_FIELD:
4255 : {
4256 : std::unique_ptr<OGRFieldDefn> poFieldDef =
4257 22 : GetLayerDefn()->StealFieldDefn(iField);
4258 11 : if (poFieldDef)
4259 : {
4260 11 : oFieldChange.poFieldDefn = std::move(poFieldDef);
4261 : }
4262 : else
4263 : {
4264 0 : CPLError(CE_Failure, CPLE_AppDefined,
4265 : "Failed to delete added field %s", pszName);
4266 : }
4267 11 : break;
4268 : }
4269 : }
4270 : }
4271 : else
4272 : {
4273 0 : CPLError(CE_Failure, CPLE_AppDefined,
4274 : "Failed to restore field %s (field not found at index %d)",
4275 : pszName, iField);
4276 : }
4277 : }
4278 :
4279 : // Remove from the storage the deleted fields that have been restored
4280 309 : for (const auto &i : toBeRemoved)
4281 : {
4282 136 : m_apoFieldDefnChanges.erase(m_apoFieldDefnChanges.begin() + i);
4283 : }
4284 :
4285 : /**********************************************************************/
4286 : /* Reset geometry fields to their previous state. */
4287 : /**********************************************************************/
4288 :
4289 173 : bSavepointFound = false;
4290 :
4291 : // Loop through all changed geometry fields and reset them to their previous state.
4292 173 : for (int i = static_cast<int>(m_apoGeomFieldDefnChanges.size()) - 1; i >= 0;
4293 : i--)
4294 : {
4295 0 : auto &oGeomFieldChange = m_apoGeomFieldDefnChanges[i];
4296 :
4297 0 : if (!osSavepointName.empty())
4298 : {
4299 0 : if (oGeomFieldChange.osSavepointName == osSavepointName)
4300 : {
4301 0 : bSavepointFound = true;
4302 : }
4303 0 : else if (bSavepointFound)
4304 : {
4305 0 : continue;
4306 : }
4307 : }
4308 0 : const char *pszName = oGeomFieldChange.poFieldDefn->GetNameRef();
4309 0 : const int iGeomField = oGeomFieldChange.iField;
4310 0 : if (iGeomField >= 0)
4311 : {
4312 0 : switch (oGeomFieldChange.eChangeType)
4313 : {
4314 0 : case FieldChangeType::DELETE_FIELD:
4315 : case FieldChangeType::ALTER_FIELD:
4316 : {
4317 : // Currently not handled by OGR for geometry fields
4318 0 : break;
4319 : }
4320 0 : case FieldChangeType::ADD_FIELD:
4321 : {
4322 : std::unique_ptr<OGRGeomFieldDefn> poGeomFieldDef =
4323 0 : GetLayerDefn()->StealGeomFieldDefn(
4324 0 : oGeomFieldChange.iField);
4325 0 : if (poGeomFieldDef)
4326 : {
4327 : oGeomFieldChange.poFieldDefn =
4328 0 : std::move(poGeomFieldDef);
4329 : }
4330 : else
4331 : {
4332 0 : CPLError(CE_Failure, CPLE_AppDefined,
4333 : "Failed to delete added geometry field %s",
4334 : pszName);
4335 : }
4336 0 : break;
4337 : }
4338 : }
4339 : }
4340 : else
4341 : {
4342 0 : CPLError(CE_Failure, CPLE_AppDefined,
4343 : "Failed to restore geometry field %s (field not found at "
4344 : "index %d)",
4345 : pszName, oGeomFieldChange.iField);
4346 : }
4347 : }
4348 173 : }
4349 :
4350 : //! @endcond
4351 :
4352 : /************************************************************************/
4353 : /* OGRLayer::ResetReading() */
4354 : /************************************************************************/
4355 :
4356 : /**
4357 : \fn void OGRLayer::ResetReading();
4358 :
4359 : \brief Reset feature reading to start on the first feature.
4360 :
4361 : This affects GetNextFeature() and GetArrowStream().
4362 :
4363 : This method is the same as the C function OGR_L_ResetReading().
4364 : */
4365 :
4366 : /************************************************************************/
4367 : /* OGR_L_ResetReading() */
4368 : /************************************************************************/
4369 :
4370 : /**
4371 : \brief Reset feature reading to start on the first feature.
4372 :
4373 : This affects GetNextFeature() and GetArrowStream().
4374 :
4375 : This function is the same as the C++ method OGRLayer::ResetReading().
4376 :
4377 : @param hLayer handle to the layer on which features are read.
4378 : */
4379 :
4380 18743 : void OGR_L_ResetReading(OGRLayerH hLayer)
4381 :
4382 : {
4383 18743 : VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
4384 :
4385 : #ifdef OGRAPISPY_ENABLED
4386 18743 : if (bOGRAPISpyEnabled)
4387 2 : OGRAPISpy_L_ResetReading(hLayer);
4388 : #endif
4389 :
4390 18743 : OGRLayer::FromHandle(hLayer)->ResetReading();
4391 : }
4392 :
4393 : /************************************************************************/
4394 : /* InitializeIndexSupport() */
4395 : /* */
4396 : /* This is only intended to be called by driver layer */
4397 : /* implementations but we don't make it protected so that the */
4398 : /* datasources can do it too if that is more appropriate. */
4399 : /************************************************************************/
4400 :
4401 : //! @cond Doxygen_Suppress
4402 : OGRErr
4403 837 : OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
4404 :
4405 : {
4406 : #ifdef HAVE_MITAB
4407 : OGRErr eErr;
4408 :
4409 837 : if (m_poAttrIndex != nullptr)
4410 663 : return OGRERR_NONE;
4411 :
4412 174 : m_poAttrIndex = OGRCreateDefaultLayerIndex();
4413 :
4414 174 : eErr = m_poAttrIndex->Initialize(pszFilename, this);
4415 174 : if (eErr != OGRERR_NONE)
4416 : {
4417 0 : delete m_poAttrIndex;
4418 0 : m_poAttrIndex = nullptr;
4419 : }
4420 :
4421 174 : return eErr;
4422 : #else
4423 : return OGRERR_FAILURE;
4424 : #endif
4425 : }
4426 :
4427 : //! @endcond
4428 :
4429 : /************************************************************************/
4430 : /* SyncToDisk() */
4431 : /************************************************************************/
4432 :
4433 : /**
4434 : \brief Flush pending changes to disk.
4435 :
4436 : This call is intended to force the layer to flush any pending writes to
4437 : disk, and leave the disk file in a consistent state. It would not normally
4438 : have any effect on read-only datasources.
4439 :
4440 : Some layers do not implement this method, and will still return
4441 : OGRERR_NONE. The default implementation just returns OGRERR_NONE. An error
4442 : is only returned if an error occurs while attempting to flush to disk.
4443 :
4444 : In any event, you should always close any opened datasource with
4445 : OGRDataSource::DestroyDataSource() that will ensure all data is correctly flushed.
4446 :
4447 : This method is the same as the C function OGR_L_SyncToDisk().
4448 :
4449 : @return OGRERR_NONE if no error occurs (even if nothing is done) or an
4450 : error code.
4451 : */
4452 :
4453 6568 : OGRErr OGRLayer::SyncToDisk()
4454 :
4455 : {
4456 6568 : return OGRERR_NONE;
4457 : }
4458 :
4459 : /************************************************************************/
4460 : /* OGR_L_SyncToDisk() */
4461 : /************************************************************************/
4462 :
4463 : /**
4464 : \brief Flush pending changes to disk.
4465 :
4466 : This call is intended to force the layer to flush any pending writes to
4467 : disk, and leave the disk file in a consistent state. It would not normally
4468 : have any effect on read-only datasources.
4469 :
4470 : Some layers do not implement this method, and will still return
4471 : OGRERR_NONE. The default implementation just returns OGRERR_NONE. An error
4472 : is only returned if an error occurs while attempting to flush to disk.
4473 :
4474 : In any event, you should always close any opened datasource with
4475 : OGR_DS_Destroy() that will ensure all data is correctly flushed.
4476 :
4477 : This method is the same as the C++ method OGRLayer::SyncToDisk()
4478 :
4479 : @param hLayer handle to the layer
4480 :
4481 : @return OGRERR_NONE if no error occurs (even if nothing is done) or an
4482 : error code.
4483 : */
4484 :
4485 251 : OGRErr OGR_L_SyncToDisk(OGRLayerH hLayer)
4486 :
4487 : {
4488 251 : VALIDATE_POINTER1(hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE);
4489 :
4490 : #ifdef OGRAPISPY_ENABLED
4491 251 : if (bOGRAPISpyEnabled)
4492 2 : OGRAPISpy_L_SyncToDisk(hLayer);
4493 : #endif
4494 :
4495 251 : return OGRLayer::FromHandle(hLayer)->SyncToDisk();
4496 : }
4497 :
4498 : /************************************************************************/
4499 : /* DeleteFeature() */
4500 : /************************************************************************/
4501 :
4502 : /**
4503 : \brief Delete feature from layer.
4504 :
4505 : The feature with the indicated feature id is deleted from the layer if
4506 : supported by the driver. Most drivers do not support feature deletion,
4507 : and will return OGRERR_UNSUPPORTED_OPERATION. The TestCapability()
4508 : layer method may be called with OLCDeleteFeature to check if the driver
4509 : supports feature deletion.
4510 :
4511 : This method is the same as the C function OGR_L_DeleteFeature().
4512 :
4513 : @param nFID the feature id to be deleted from the layer
4514 :
4515 : @return OGRERR_NONE if the operation works, otherwise an appropriate error
4516 : code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
4517 :
4518 : */
4519 :
4520 432 : OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
4521 : {
4522 432 : return OGRERR_UNSUPPORTED_OPERATION;
4523 : }
4524 :
4525 : /************************************************************************/
4526 : /* OGR_L_DeleteFeature() */
4527 : /************************************************************************/
4528 :
4529 : /**
4530 : \brief Delete feature from layer.
4531 :
4532 : The feature with the indicated feature id is deleted from the layer if
4533 : supported by the driver. Most drivers do not support feature deletion,
4534 : and will return OGRERR_UNSUPPORTED_OPERATION. The OGR_L_TestCapability()
4535 : function may be called with OLCDeleteFeature to check if the driver
4536 : supports feature deletion.
4537 :
4538 : This method is the same as the C++ method OGRLayer::DeleteFeature().
4539 :
4540 : @param hLayer handle to the layer
4541 : @param nFID the feature id to be deleted from the layer
4542 :
4543 : @return OGRERR_NONE if the operation works, otherwise an appropriate error
4544 : code (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
4545 : */
4546 :
4547 3356 : OGRErr OGR_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
4548 :
4549 : {
4550 3356 : VALIDATE_POINTER1(hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE);
4551 :
4552 : #ifdef OGRAPISPY_ENABLED
4553 3356 : if (bOGRAPISpyEnabled)
4554 2 : OGRAPISpy_L_DeleteFeature(hLayer, nFID);
4555 : #endif
4556 :
4557 3356 : return OGRLayer::FromHandle(hLayer)->DeleteFeature(nFID);
4558 : }
4559 :
4560 : /************************************************************************/
4561 : /* GetFeaturesRead() */
4562 : /************************************************************************/
4563 :
4564 : //! @cond Doxygen_Suppress
4565 0 : GIntBig OGRLayer::GetFeaturesRead()
4566 :
4567 : {
4568 0 : return m_nFeaturesRead;
4569 : }
4570 :
4571 : //! @endcond
4572 :
4573 : /************************************************************************/
4574 : /* OGR_L_GetFeaturesRead() */
4575 : /************************************************************************/
4576 :
4577 0 : GIntBig OGR_L_GetFeaturesRead(OGRLayerH hLayer)
4578 :
4579 : {
4580 0 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeaturesRead", 0);
4581 :
4582 0 : return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
4583 : }
4584 :
4585 : /************************************************************************/
4586 : /* GetFIDColumn */
4587 : /************************************************************************/
4588 :
4589 : /**
4590 : \brief This method returns the name of the underlying database column being used as the FID column, or "" if not supported.
4591 :
4592 : This method is the same as the C function OGR_L_GetFIDColumn().
4593 :
4594 : @return fid column name.
4595 : */
4596 :
4597 9668 : const char *OGRLayer::GetFIDColumn() const
4598 :
4599 : {
4600 9668 : return "";
4601 : }
4602 :
4603 : /************************************************************************/
4604 : /* OGR_L_GetFIDColumn() */
4605 : /************************************************************************/
4606 :
4607 : /**
4608 : \brief This method returns the name of the underlying database column being used as the FID column, or "" if not supported.
4609 :
4610 : This method is the same as the C++ method OGRLayer::GetFIDColumn()
4611 :
4612 : @param hLayer handle to the layer
4613 : @return fid column name.
4614 : */
4615 :
4616 423 : const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
4617 :
4618 : {
4619 423 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
4620 :
4621 : #ifdef OGRAPISPY_ENABLED
4622 423 : if (bOGRAPISpyEnabled)
4623 2 : OGRAPISpy_L_GetFIDColumn(hLayer);
4624 : #endif
4625 :
4626 423 : return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
4627 : }
4628 :
4629 : /************************************************************************/
4630 : /* GetGeometryColumn() */
4631 : /************************************************************************/
4632 :
4633 : /**
4634 : \brief This method returns the name of the underlying database column being used as the geometry column, or "" if not supported.
4635 :
4636 : For layers with multiple geometry fields, this method only returns the name
4637 : of the first geometry column. For other columns, use
4638 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(i)->GetNameRef().
4639 :
4640 : This method is the same as the C function OGR_L_GetGeometryColumn().
4641 :
4642 : @return geometry column name.
4643 : */
4644 :
4645 3880 : const char *OGRLayer::GetGeometryColumn() const
4646 :
4647 : {
4648 3880 : const auto poLayerDefn = GetLayerDefn();
4649 3880 : if (poLayerDefn->GetGeomFieldCount() > 0)
4650 3788 : return poLayerDefn->GetGeomFieldDefn(0)->GetNameRef();
4651 : else
4652 92 : return "";
4653 : }
4654 :
4655 : /************************************************************************/
4656 : /* OGR_L_GetGeometryColumn() */
4657 : /************************************************************************/
4658 :
4659 : /**
4660 : \brief This method returns the name of the underlying database column being used as the geometry column, or "" if not supported.
4661 :
4662 : For layers with multiple geometry fields, this method only returns the geometry
4663 : type of the first geometry column. For other columns, use
4664 : OGR_GFld_GetNameRef(OGR_FD_GetGeomFieldDefn(OGR_L_GetLayerDefn(hLayer), i)).
4665 :
4666 : This method is the same as the C++ method OGRLayer::GetGeometryColumn()
4667 :
4668 : @param hLayer handle to the layer
4669 : @return geometry column name.
4670 : */
4671 :
4672 703 : const char *OGR_L_GetGeometryColumn(OGRLayerH hLayer)
4673 :
4674 : {
4675 703 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryColumn", nullptr);
4676 :
4677 : #ifdef OGRAPISPY_ENABLED
4678 703 : if (bOGRAPISpyEnabled)
4679 2 : OGRAPISpy_L_GetGeometryColumn(hLayer);
4680 : #endif
4681 :
4682 703 : return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
4683 : }
4684 :
4685 : /************************************************************************/
4686 : /* GetStyleTable() */
4687 : /************************************************************************/
4688 :
4689 : /**
4690 : \brief Returns layer style table.
4691 :
4692 : This method is the same as the C function OGR_L_GetStyleTable().
4693 :
4694 : @return pointer to a style table which should not be modified or freed by the
4695 : caller.
4696 : */
4697 :
4698 1210 : OGRStyleTable *OGRLayer::GetStyleTable()
4699 : {
4700 1210 : return m_poStyleTable;
4701 : }
4702 :
4703 : /************************************************************************/
4704 : /* SetStyleTableDirectly() */
4705 : /************************************************************************/
4706 :
4707 : /**
4708 : \brief Set layer style table.
4709 :
4710 : This method operate exactly as OGRLayer::SetStyleTable() except that it
4711 : assumes ownership of the passed table.
4712 :
4713 : This method is the same as the C function OGR_L_SetStyleTableDirectly().
4714 :
4715 : @param poStyleTable pointer to style table to set
4716 : */
4717 :
4718 0 : void OGRLayer::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
4719 : {
4720 0 : if (m_poStyleTable)
4721 0 : delete m_poStyleTable;
4722 0 : m_poStyleTable = poStyleTable;
4723 0 : }
4724 :
4725 : /************************************************************************/
4726 : /* SetStyleTable() */
4727 : /************************************************************************/
4728 :
4729 : /**
4730 : \brief Set layer style table.
4731 :
4732 : This method operate exactly as OGRLayer::SetStyleTableDirectly() except
4733 : that it does not assume ownership of the passed table.
4734 :
4735 : This method is the same as the C function OGR_L_SetStyleTable().
4736 :
4737 : @param poStyleTable pointer to style table to set
4738 : */
4739 :
4740 1207 : void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
4741 : {
4742 1207 : if (m_poStyleTable)
4743 0 : delete m_poStyleTable;
4744 1207 : if (poStyleTable)
4745 1 : m_poStyleTable = poStyleTable->Clone();
4746 1207 : }
4747 :
4748 : /************************************************************************/
4749 : /* OGR_L_GetStyleTable() */
4750 : /************************************************************************/
4751 :
4752 3 : OGRStyleTableH OGR_L_GetStyleTable(OGRLayerH hLayer)
4753 :
4754 : {
4755 3 : VALIDATE_POINTER1(hLayer, "OGR_L_GetStyleTable", nullptr);
4756 :
4757 : return reinterpret_cast<OGRStyleTableH>(
4758 3 : OGRLayer::FromHandle(hLayer)->GetStyleTable());
4759 : }
4760 :
4761 : /************************************************************************/
4762 : /* OGR_L_SetStyleTableDirectly() */
4763 : /************************************************************************/
4764 :
4765 0 : void OGR_L_SetStyleTableDirectly(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
4766 :
4767 : {
4768 0 : VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTableDirectly");
4769 :
4770 0 : OGRLayer::FromHandle(hLayer)->SetStyleTableDirectly(
4771 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
4772 : }
4773 :
4774 : /************************************************************************/
4775 : /* OGR_L_SetStyleTable() */
4776 : /************************************************************************/
4777 :
4778 1 : void OGR_L_SetStyleTable(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
4779 :
4780 : {
4781 1 : VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTable");
4782 1 : VALIDATE_POINTER0(hStyleTable, "OGR_L_SetStyleTable");
4783 :
4784 1 : OGRLayer::FromHandle(hLayer)->SetStyleTable(
4785 1 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
4786 : }
4787 :
4788 : /************************************************************************/
4789 : /* GetName() */
4790 : /************************************************************************/
4791 :
4792 : /**
4793 : \brief Return the layer name.
4794 :
4795 : This returns the same content as GetLayerDefn()->OGRFeatureDefn::GetName(), but for a
4796 : few drivers, calling GetName() directly can avoid lengthy layer
4797 : definition initialization.
4798 :
4799 : This method is the same as the C function OGR_L_GetName().
4800 :
4801 : If this method is derived in a driver, it must be done such that it
4802 : returns the same content as GetLayerDefn()->OGRFeatureDefn::GetName().
4803 :
4804 : @return the layer name (must not been freed)
4805 : */
4806 :
4807 1509150 : const char *OGRLayer::GetName() const
4808 :
4809 : {
4810 1509150 : return GetLayerDefn()->GetName();
4811 : }
4812 :
4813 : /************************************************************************/
4814 : /* OGR_L_GetName() */
4815 : /************************************************************************/
4816 :
4817 : /**
4818 : \brief Return the layer name.
4819 :
4820 : This returns the same content as OGR_FD_GetName(OGR_L_GetLayerDefn(hLayer)),
4821 : but for a few drivers, calling OGR_L_GetName() directly can avoid lengthy
4822 : layer definition initialization.
4823 :
4824 : This function is the same as the C++ method OGRLayer::GetName().
4825 :
4826 : @param hLayer handle to the layer.
4827 : @return the layer name (must not been freed)
4828 : */
4829 :
4830 1348 : const char *OGR_L_GetName(OGRLayerH hLayer)
4831 :
4832 : {
4833 1348 : VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
4834 :
4835 : #ifdef OGRAPISPY_ENABLED
4836 1348 : if (bOGRAPISpyEnabled)
4837 2 : OGRAPISpy_L_GetName(hLayer);
4838 : #endif
4839 :
4840 1348 : return OGRLayer::FromHandle(hLayer)->GetName();
4841 : }
4842 :
4843 : /************************************************************************/
4844 : /* GetGeomType() */
4845 : /************************************************************************/
4846 :
4847 : /**
4848 : \brief Return the layer geometry type.
4849 :
4850 : This returns the same result as GetLayerDefn()->OGRFeatureDefn::GetGeomType(), but for a
4851 : few drivers, calling GetGeomType() directly can avoid lengthy layer
4852 : definition initialization.
4853 :
4854 : Note that even if this method is const (since GDAL 3.12), there is no guarantee
4855 : it can be safely called by concurrent threads on the same GDALDataset object.
4856 :
4857 : For layers with multiple geometry fields, this method only returns the geometry
4858 : type of the first geometry column. For other columns, use
4859 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(i)->GetType().
4860 : For layers without any geometry field, this method returns wkbNone.
4861 :
4862 : This method is the same as the C function OGR_L_GetGeomType().
4863 :
4864 : If this method is derived in a driver, it must be done such that it
4865 : returns the same content as GetLayerDefn()->OGRFeatureDefn::GetGeomType().
4866 :
4867 : @return the geometry type
4868 : */
4869 :
4870 219716 : OGRwkbGeometryType OGRLayer::GetGeomType() const
4871 : {
4872 219716 : const OGRFeatureDefn *poLayerDefn = GetLayerDefn();
4873 219716 : if (poLayerDefn == nullptr)
4874 : {
4875 0 : CPLDebug("OGR", "GetLayerType() returns NULL !");
4876 0 : return wkbUnknown;
4877 : }
4878 219716 : return poLayerDefn->GetGeomType();
4879 : }
4880 :
4881 : /************************************************************************/
4882 : /* OGR_L_GetGeomType() */
4883 : /************************************************************************/
4884 :
4885 : /**
4886 : \brief Return the layer geometry type.
4887 :
4888 : This returns the same result as OGR_FD_GetGeomType(OGR_L_GetLayerDefn(hLayer)),
4889 : but for a few drivers, calling OGR_L_GetGeomType() directly can avoid lengthy
4890 : layer definition initialization.
4891 :
4892 : For layers with multiple geometry fields, this method only returns the geometry
4893 : type of the first geometry column. For other columns, use
4894 : OGR_GFld_GetType(OGR_FD_GetGeomFieldDefn(OGR_L_GetLayerDefn(hLayer), i)).
4895 : For layers without any geometry field, this method returns wkbNone.
4896 :
4897 : This function is the same as the C++ method OGRLayer::GetGeomType().
4898 :
4899 : @param hLayer handle to the layer.
4900 : @return the geometry type
4901 : */
4902 :
4903 1327 : OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
4904 :
4905 : {
4906 1327 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
4907 :
4908 : #ifdef OGRAPISPY_ENABLED
4909 1327 : if (bOGRAPISpyEnabled)
4910 2 : OGRAPISpy_L_GetGeomType(hLayer);
4911 : #endif
4912 :
4913 1327 : OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
4914 1327 : if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
4915 : {
4916 1 : eType = OGR_GT_GetLinear(eType);
4917 : }
4918 1327 : return eType;
4919 : }
4920 :
4921 : /************************************************************************/
4922 : /* SetIgnoredFields() */
4923 : /************************************************************************/
4924 :
4925 : /**
4926 : \brief Set which fields can be omitted when retrieving features from the layer.
4927 :
4928 : If the driver supports this functionality (testable using OLCIgnoreFields capability), it will not fetch the specified fields
4929 : in subsequent calls to GetFeature() / GetNextFeature() and thus save some processing time and/or bandwidth.
4930 :
4931 : Besides field names of the layers, the following special fields can be passed: "OGR_GEOMETRY" to ignore geometry and
4932 : "OGR_STYLE" to ignore layer style.
4933 :
4934 : By default, no fields are ignored.
4935 :
4936 : Note that fields that are used in an attribute filter should generally not be set as
4937 : ignored fields, as most drivers (such as those relying on the OGR SQL engine)
4938 : will be unable to correctly evaluate the attribute filter.
4939 :
4940 : This method is the same as the C function OGR_L_SetIgnoredFields()
4941 :
4942 : @param papszFields an array of field names terminated by NULL item. If NULL is passed, the ignored list is cleared.
4943 : @return OGRERR_NONE if all field names have been resolved (even if the driver does not support this method)
4944 : */
4945 :
4946 8293 : OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
4947 : {
4948 8293 : OGRFeatureDefn *poDefn = GetLayerDefn();
4949 :
4950 : // first set everything as *not* ignored
4951 62377 : for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
4952 : {
4953 54084 : poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
4954 : }
4955 17506 : for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
4956 : {
4957 9213 : poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
4958 : }
4959 8293 : poDefn->SetStyleIgnored(FALSE);
4960 :
4961 : // ignore some fields
4962 13909 : for (const char *pszFieldName : cpl::Iterate(papszFields))
4963 : {
4964 : // check special fields
4965 5616 : if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
4966 161 : poDefn->SetGeometryIgnored(TRUE);
4967 5455 : else if (EQUAL(pszFieldName, "OGR_STYLE"))
4968 13 : poDefn->SetStyleIgnored(TRUE);
4969 : else
4970 : {
4971 : // check ordinary fields
4972 5442 : int iField = poDefn->GetFieldIndex(pszFieldName);
4973 5442 : if (iField == -1)
4974 : {
4975 : // check geometry field
4976 1043 : iField = poDefn->GetGeomFieldIndex(pszFieldName);
4977 1043 : if (iField == -1)
4978 : {
4979 0 : return OGRERR_FAILURE;
4980 : }
4981 : else
4982 1043 : poDefn->GetGeomFieldDefn(iField)->SetIgnored(TRUE);
4983 : }
4984 : else
4985 4399 : poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
4986 : }
4987 : }
4988 :
4989 8293 : return OGRERR_NONE;
4990 : }
4991 :
4992 : /************************************************************************/
4993 : /* OGR_L_SetIgnoredFields() */
4994 : /************************************************************************/
4995 :
4996 : /**
4997 : \brief Set which fields can be omitted when retrieving features from the layer.
4998 :
4999 : If the driver supports this functionality (testable using OLCIgnoreFields capability), it will not fetch the specified fields
5000 : in subsequent calls to GetFeature() / GetNextFeature() and thus save some processing time and/or bandwidth.
5001 :
5002 : Besides field names of the layers, the following special fields can be passed: "OGR_GEOMETRY" to ignore geometry and
5003 : "OGR_STYLE" to ignore layer style.
5004 :
5005 : By default, no fields are ignored.
5006 :
5007 : Note that fields that are used in an attribute filter should generally not be set as
5008 : ignored fields, as most drivers (such as those relying on the OGR SQL engine)
5009 : will be unable to correctly evaluate the attribute filter.
5010 :
5011 : This method is the same as the C++ method OGRLayer::SetIgnoredFields()
5012 :
5013 : @param hLayer handle to the layer
5014 : @param papszFields an array of field names terminated by NULL item. If NULL is passed, the ignored list is cleared.
5015 : @return OGRERR_NONE if all field names have been resolved (even if the driver does not support this method)
5016 : */
5017 :
5018 322 : OGRErr OGR_L_SetIgnoredFields(OGRLayerH hLayer, const char **papszFields)
5019 :
5020 : {
5021 322 : VALIDATE_POINTER1(hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE);
5022 :
5023 : #ifdef OGRAPISPY_ENABLED
5024 322 : if (bOGRAPISpyEnabled)
5025 2 : OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
5026 : #endif
5027 :
5028 322 : return OGRLayer::FromHandle(hLayer)->SetIgnoredFields(papszFields);
5029 : }
5030 :
5031 : /************************************************************************/
5032 : /* Rename() */
5033 : /************************************************************************/
5034 :
5035 : /** Rename layer.
5036 : *
5037 : * This operation is implemented only by layers that expose the OLCRename
5038 : * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
5039 : *
5040 : * This operation will fail if a layer with the new name already exists.
5041 : *
5042 : * On success, GetDescription() and GetLayerDefn()->GetName() will return
5043 : * pszNewName.
5044 : *
5045 : * Renaming the layer may interrupt current feature iteration.
5046 : *
5047 : * @param pszNewName New layer name. Must not be NULL.
5048 : * @return OGRERR_NONE in case of success
5049 : *
5050 : * @since GDAL 3.5
5051 : */
5052 0 : OGRErr OGRLayer::Rename(CPL_UNUSED const char *pszNewName)
5053 : {
5054 0 : CPLError(CE_Failure, CPLE_NotSupported,
5055 : "Rename() not supported by this layer.");
5056 :
5057 0 : return OGRERR_UNSUPPORTED_OPERATION;
5058 : }
5059 :
5060 : /************************************************************************/
5061 : /* OGR_L_Rename() */
5062 : /************************************************************************/
5063 :
5064 : /** Rename layer.
5065 : *
5066 : * This operation is implemented only by layers that expose the OLCRename
5067 : * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
5068 : *
5069 : * This operation will fail if a layer with the new name already exists.
5070 : *
5071 : * On success, GetDescription() and GetLayerDefn()->GetName() will return
5072 : * pszNewName.
5073 : *
5074 : * Renaming the layer may interrupt current feature iteration.
5075 : *
5076 : * @param hLayer Layer to rename.
5077 : * @param pszNewName New layer name. Must not be NULL.
5078 : * @return OGRERR_NONE in case of success
5079 : *
5080 : * @since GDAL 3.5
5081 : */
5082 30 : OGRErr OGR_L_Rename(OGRLayerH hLayer, const char *pszNewName)
5083 :
5084 : {
5085 30 : VALIDATE_POINTER1(hLayer, "OGR_L_Rename", OGRERR_INVALID_HANDLE);
5086 30 : VALIDATE_POINTER1(pszNewName, "OGR_L_Rename", OGRERR_FAILURE);
5087 :
5088 30 : return OGRLayer::FromHandle(hLayer)->Rename(pszNewName);
5089 : }
5090 :
5091 : /************************************************************************/
5092 : /* helper functions for layer overlay methods */
5093 : /************************************************************************/
5094 :
5095 78 : static OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
5096 : {
5097 78 : OGRErr ret = OGRERR_NONE;
5098 78 : OGRGeometry *g = pLayer->GetSpatialFilter();
5099 78 : *ppGeometry = g ? g->clone() : nullptr;
5100 78 : return ret;
5101 : }
5102 :
5103 99 : static OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
5104 : {
5105 99 : OGRErr ret = OGRERR_NONE;
5106 99 : int n = poDefn->GetFieldCount();
5107 99 : if (n > 0)
5108 : {
5109 71 : *map = static_cast<int *>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
5110 71 : if (!(*map))
5111 0 : return OGRERR_NOT_ENOUGH_MEMORY;
5112 211 : for (int i = 0; i < n; i++)
5113 140 : (*map)[i] = -1;
5114 : }
5115 99 : return ret;
5116 : }
5117 :
5118 55 : static OGRErr set_result_schema(OGRLayer *pLayerResult,
5119 : OGRFeatureDefn *poDefnInput,
5120 : OGRFeatureDefn *poDefnMethod, int *mapInput,
5121 : int *mapMethod, bool combined,
5122 : const char *const *papszOptions)
5123 : {
5124 55 : if (!CPLTestBool(CSLFetchNameValueDef(papszOptions, "ADD_FIELDS", "YES")))
5125 0 : return OGRERR_NONE;
5126 :
5127 55 : OGRErr ret = OGRERR_NONE;
5128 55 : OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
5129 : const char *pszInputPrefix =
5130 55 : CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
5131 : const char *pszMethodPrefix =
5132 55 : CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
5133 : const bool bSkipFailures =
5134 55 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5135 55 : if (poDefnResult->GetFieldCount() > 0)
5136 : {
5137 : // the user has defined the schema of the output layer
5138 17 : if (mapInput)
5139 : {
5140 48 : for (int iField = 0; iField < poDefnInput->GetFieldCount();
5141 : iField++)
5142 : {
5143 : CPLString osName(
5144 31 : poDefnInput->GetFieldDefn(iField)->GetNameRef());
5145 31 : if (pszInputPrefix != nullptr)
5146 17 : osName = pszInputPrefix + osName;
5147 31 : mapInput[iField] = poDefnResult->GetFieldIndex(osName);
5148 : }
5149 : }
5150 17 : if (!mapMethod)
5151 4 : return ret;
5152 : // cppcheck-suppress nullPointer
5153 40 : for (int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++)
5154 : {
5155 : // cppcheck-suppress nullPointer
5156 27 : CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
5157 27 : if (pszMethodPrefix != nullptr)
5158 17 : osName = pszMethodPrefix + osName;
5159 27 : mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
5160 : }
5161 : }
5162 : else
5163 : {
5164 : // use schema from the input layer or from input and method layers
5165 38 : const int nFieldsInput = poDefnInput->GetFieldCount();
5166 :
5167 : // If no prefix is specified and we have input+method layers, make
5168 : // sure we will generate unique field names
5169 38 : std::set<std::string> oSetInputFieldNames;
5170 38 : std::set<std::string> oSetMethodFieldNames;
5171 38 : if (poDefnMethod != nullptr && pszInputPrefix == nullptr &&
5172 : pszMethodPrefix == nullptr)
5173 : {
5174 67 : for (int iField = 0; iField < nFieldsInput; iField++)
5175 : {
5176 : oSetInputFieldNames.insert(
5177 36 : poDefnInput->GetFieldDefn(iField)->GetNameRef());
5178 : }
5179 31 : const int nFieldsMethod = poDefnMethod->GetFieldCount();
5180 65 : for (int iField = 0; iField < nFieldsMethod; iField++)
5181 : {
5182 : oSetMethodFieldNames.insert(
5183 34 : poDefnMethod->GetFieldDefn(iField)->GetNameRef());
5184 : }
5185 : }
5186 :
5187 38 : const bool bAddInputFields = CPLTestBool(
5188 : CSLFetchNameValueDef(papszOptions, "ADD_INPUT_FIELDS", "YES"));
5189 38 : if (bAddInputFields)
5190 : {
5191 70 : for (int iField = 0; iField < nFieldsInput; iField++)
5192 : {
5193 36 : OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
5194 36 : if (pszInputPrefix != nullptr)
5195 0 : oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix,
5196 : oFieldDefn.GetNameRef()));
5197 58 : else if (!oSetMethodFieldNames.empty() &&
5198 58 : oSetMethodFieldNames.find(oFieldDefn.GetNameRef()) !=
5199 58 : oSetMethodFieldNames.end())
5200 : {
5201 : // Field of same name present in method layer
5202 13 : oFieldDefn.SetName(
5203 : CPLSPrintf("input_%s", oFieldDefn.GetNameRef()));
5204 : }
5205 36 : ret = pLayerResult->CreateField(&oFieldDefn);
5206 36 : if (ret != OGRERR_NONE)
5207 : {
5208 0 : if (!bSkipFailures)
5209 0 : return ret;
5210 : else
5211 : {
5212 0 : CPLErrorReset();
5213 0 : ret = OGRERR_NONE;
5214 : }
5215 : }
5216 36 : if (mapInput)
5217 36 : mapInput[iField] =
5218 36 : pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
5219 : }
5220 : }
5221 :
5222 38 : if (!combined)
5223 11 : return ret;
5224 27 : if (!mapMethod)
5225 12 : return ret;
5226 15 : if (!poDefnMethod)
5227 0 : return ret;
5228 :
5229 15 : const bool bAddMethodFields = CPLTestBool(
5230 : CSLFetchNameValueDef(papszOptions, "ADD_METHOD_FIELDS", "YES"));
5231 15 : if (bAddMethodFields)
5232 : {
5233 11 : const int nFieldsMethod = poDefnMethod->GetFieldCount();
5234 29 : for (int iField = 0; iField < nFieldsMethod; iField++)
5235 : {
5236 18 : OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
5237 18 : if (pszMethodPrefix != nullptr)
5238 0 : oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix,
5239 : oFieldDefn.GetNameRef()));
5240 36 : else if (!oSetInputFieldNames.empty() &&
5241 36 : oSetInputFieldNames.find(oFieldDefn.GetNameRef()) !=
5242 36 : oSetInputFieldNames.end())
5243 : {
5244 : // Field of same name present in method layer
5245 11 : oFieldDefn.SetName(
5246 : CPLSPrintf("method_%s", oFieldDefn.GetNameRef()));
5247 : }
5248 18 : ret = pLayerResult->CreateField(&oFieldDefn);
5249 18 : if (ret != OGRERR_NONE)
5250 : {
5251 0 : if (!bSkipFailures)
5252 0 : return ret;
5253 : else
5254 : {
5255 0 : CPLErrorReset();
5256 0 : ret = OGRERR_NONE;
5257 : }
5258 : }
5259 18 : mapMethod[iField] =
5260 18 : pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
5261 : }
5262 : }
5263 : }
5264 28 : return ret;
5265 : }
5266 :
5267 309 : static OGRGeometry *set_filter_from(OGRLayer *pLayer,
5268 : OGRGeometry *pGeometryExistingFilter,
5269 : OGRFeature *pFeature)
5270 : {
5271 309 : OGRGeometry *geom = pFeature->GetGeometryRef();
5272 309 : if (!geom)
5273 0 : return nullptr;
5274 309 : if (pGeometryExistingFilter)
5275 : {
5276 0 : if (!geom->Intersects(pGeometryExistingFilter))
5277 0 : return nullptr;
5278 0 : OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
5279 0 : if (intersection)
5280 : {
5281 0 : pLayer->SetSpatialFilter(intersection);
5282 0 : delete intersection;
5283 : }
5284 : else
5285 0 : return nullptr;
5286 : }
5287 : else
5288 : {
5289 309 : pLayer->SetSpatialFilter(geom);
5290 : }
5291 309 : return geom;
5292 : }
5293 :
5294 26 : static OGRGeometry *promote_to_multi(OGRGeometry *poGeom)
5295 : {
5296 26 : OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
5297 26 : if (eType == wkbPoint)
5298 4 : return OGRGeometryFactory::forceToMultiPoint(poGeom);
5299 22 : else if (eType == wkbPolygon)
5300 22 : return OGRGeometryFactory::forceToMultiPolygon(poGeom);
5301 0 : else if (eType == wkbLineString)
5302 0 : return OGRGeometryFactory::forceToMultiLineString(poGeom);
5303 : else
5304 0 : return poGeom;
5305 : }
5306 :
5307 : /************************************************************************/
5308 : /* Intersection() */
5309 : /************************************************************************/
5310 : /**
5311 : * \brief Intersection of two layers.
5312 : *
5313 : * The result layer contains features whose geometries represent areas
5314 : * that are common between features in the input layer and in the
5315 : * method layer. The features in the result layer have attributes from
5316 : * both input and method layers. The schema of the result layer can be
5317 : * set by the user or, if it is empty, is initialized to contain all
5318 : * fields in the input and method layers.
5319 : *
5320 : * \note If the schema of the result is set by user and contains
5321 : * fields that have the same name as a field in input and in method
5322 : * layer, then the attribute in the result feature will get the value
5323 : * from the feature of the method layer.
5324 : *
5325 : * \note For best performance use the minimum amount of features in
5326 : * the method layer and copy it into a memory layer.
5327 : *
5328 : * \note This method relies on GEOS support. Do not use unless the
5329 : * GEOS support is compiled in.
5330 : *
5331 : * The recognized list of options is:
5332 : * <ul>
5333 : * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
5334 : * feature could not be inserted or a GEOS call failed.
5335 : * </li>
5336 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5337 : * into MultiPolygons, LineStrings to MultiLineStrings or
5338 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5339 : * </li>
5340 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5341 : * will be created from the fields of the input layer.
5342 : * </li>
5343 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5344 : * will be created from the fields of the method layer.
5345 : * </li>
5346 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
5347 : * geometries to pretest intersection of features of method layer
5348 : * with features of this layer.
5349 : * </li>
5350 : * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
5351 : * containment of features of method layer within the features of
5352 : * this layer. This will speed up the method significantly in some
5353 : * cases. Requires that the prepared geometries are in effect.
5354 : * </li>
5355 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
5356 : * result features with lower dimension geometry that would
5357 : * otherwise be added to the result layer. The default is YES, to add
5358 : * features with lower dimension geometry, but only if the result layer
5359 : * has an unknown geometry type.
5360 : * </li>
5361 : * </ul>
5362 : *
5363 : * This method is the same as the C function OGR_L_Intersection().
5364 : *
5365 : * @param pLayerMethod the method layer. Should not be NULL.
5366 : *
5367 : * @param pLayerResult the layer where the features resulting from the
5368 : * operation are inserted. Should not be NULL. See above the note
5369 : * about the schema.
5370 : *
5371 : * @param papszOptions NULL terminated list of options (may be NULL).
5372 : *
5373 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5374 : * reporting progress or NULL.
5375 : *
5376 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5377 : *
5378 : * @return an error code if there was an error or the execution was
5379 : * interrupted, OGRERR_NONE otherwise.
5380 : *
5381 : * @note The first geometry field is always used.
5382 : *
5383 : * @since OGR 1.10
5384 : */
5385 :
5386 8 : OGRErr OGRLayer::Intersection(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5387 : CSLConstList papszOptions,
5388 : GDALProgressFunc pfnProgress, void *pProgressArg)
5389 : {
5390 8 : OGRErr ret = OGRERR_NONE;
5391 8 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
5392 8 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
5393 8 : OGRFeatureDefn *poDefnResult = nullptr;
5394 8 : OGRGeometry *pGeometryMethodFilter = nullptr;
5395 8 : int *mapInput = nullptr;
5396 8 : int *mapMethod = nullptr;
5397 8 : OGREnvelope sEnvelopeMethod;
5398 : GBool bEnvelopeSet;
5399 8 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
5400 8 : double progress_counter = 0;
5401 8 : double progress_ticker = 0;
5402 : const bool bSkipFailures =
5403 8 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5404 8 : const bool bPromoteToMulti = CPLTestBool(
5405 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5406 8 : const bool bUsePreparedGeometries = CPLTestBool(
5407 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
5408 8 : const bool bPretestContainment = CPLTestBool(
5409 : CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
5410 8 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
5411 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
5412 :
5413 : // check for GEOS
5414 8 : if (!OGRGeometryFactory::haveGEOS())
5415 : {
5416 0 : CPLError(CE_Failure, CPLE_AppDefined,
5417 : "OGRLayer::Intersection() requires GEOS support");
5418 0 : return OGRERR_UNSUPPORTED_OPERATION;
5419 : }
5420 :
5421 : // get resources
5422 8 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5423 8 : if (ret != OGRERR_NONE)
5424 0 : goto done;
5425 8 : ret = create_field_map(poDefnInput, &mapInput);
5426 8 : if (ret != OGRERR_NONE)
5427 0 : goto done;
5428 8 : ret = create_field_map(poDefnMethod, &mapMethod);
5429 8 : if (ret != OGRERR_NONE)
5430 0 : goto done;
5431 8 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
5432 : mapMethod, true, papszOptions);
5433 8 : if (ret != OGRERR_NONE)
5434 0 : goto done;
5435 8 : poDefnResult = pLayerResult->GetLayerDefn();
5436 8 : bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
5437 8 : if (bKeepLowerDimGeom)
5438 : {
5439 : // require that the result layer is of geom type unknown
5440 6 : if (pLayerResult->GetGeomType() != wkbUnknown)
5441 : {
5442 0 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
5443 : "since the result layer does not allow it.");
5444 0 : bKeepLowerDimGeom = false;
5445 : }
5446 : }
5447 :
5448 23 : for (auto &&x : this)
5449 : {
5450 :
5451 15 : if (pfnProgress)
5452 : {
5453 2 : double p = progress_counter / progress_max;
5454 2 : if (p > progress_ticker)
5455 : {
5456 1 : if (!pfnProgress(p, "", pProgressArg))
5457 : {
5458 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5459 0 : ret = OGRERR_FAILURE;
5460 0 : goto done;
5461 : }
5462 : }
5463 2 : progress_counter += 1.0;
5464 : }
5465 :
5466 : // is it worth to proceed?
5467 15 : if (bEnvelopeSet)
5468 : {
5469 15 : OGRGeometry *x_geom = x->GetGeometryRef();
5470 15 : if (x_geom)
5471 : {
5472 15 : OGREnvelope x_env;
5473 15 : x_geom->getEnvelope(&x_env);
5474 15 : if (x_env.MaxX < sEnvelopeMethod.MinX ||
5475 15 : x_env.MaxY < sEnvelopeMethod.MinY ||
5476 15 : sEnvelopeMethod.MaxX < x_env.MinX ||
5477 15 : sEnvelopeMethod.MaxY < x_env.MinY)
5478 : {
5479 0 : continue;
5480 : }
5481 : }
5482 : else
5483 : {
5484 0 : continue;
5485 : }
5486 : }
5487 :
5488 : // set up the filter for method layer
5489 15 : CPLErrorReset();
5490 : OGRGeometry *x_geom =
5491 15 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5492 15 : if (CPLGetLastErrorType() != CE_None)
5493 : {
5494 0 : if (!bSkipFailures)
5495 : {
5496 0 : ret = OGRERR_FAILURE;
5497 0 : goto done;
5498 : }
5499 : else
5500 : {
5501 0 : CPLErrorReset();
5502 0 : ret = OGRERR_NONE;
5503 : }
5504 : }
5505 15 : if (!x_geom)
5506 : {
5507 0 : continue;
5508 : }
5509 :
5510 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
5511 15 : if (bUsePreparedGeometries)
5512 : {
5513 15 : x_prepared_geom.reset(
5514 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
5515 15 : if (!x_prepared_geom)
5516 : {
5517 0 : goto done;
5518 : }
5519 : }
5520 :
5521 32 : for (auto &&y : pLayerMethod)
5522 : {
5523 17 : OGRGeometry *y_geom = y->GetGeometryRef();
5524 17 : if (!y_geom)
5525 4 : continue;
5526 0 : OGRGeometryUniquePtr z_geom;
5527 :
5528 17 : if (x_prepared_geom)
5529 : {
5530 17 : CPLErrorReset();
5531 17 : ret = OGRERR_NONE;
5532 17 : if (bPretestContainment &&
5533 0 : OGRPreparedGeometryContains(x_prepared_geom.get(),
5534 : OGRGeometry::ToHandle(y_geom)))
5535 : {
5536 0 : if (CPLGetLastErrorType() == CE_None)
5537 0 : z_geom.reset(y_geom->clone());
5538 : }
5539 17 : else if (!(OGRPreparedGeometryIntersects(
5540 : x_prepared_geom.get(),
5541 : OGRGeometry::ToHandle(y_geom))))
5542 : {
5543 0 : if (CPLGetLastErrorType() == CE_None)
5544 : {
5545 0 : continue;
5546 : }
5547 : }
5548 17 : if (CPLGetLastErrorType() != CE_None)
5549 : {
5550 0 : if (!bSkipFailures)
5551 : {
5552 0 : ret = OGRERR_FAILURE;
5553 0 : goto done;
5554 : }
5555 : else
5556 : {
5557 0 : CPLErrorReset();
5558 0 : ret = OGRERR_NONE;
5559 0 : continue;
5560 : }
5561 : }
5562 : }
5563 17 : if (!z_geom)
5564 : {
5565 17 : CPLErrorReset();
5566 17 : z_geom.reset(x_geom->Intersection(y_geom));
5567 17 : if (CPLGetLastErrorType() != CE_None || z_geom == nullptr)
5568 : {
5569 0 : if (!bSkipFailures)
5570 : {
5571 0 : ret = OGRERR_FAILURE;
5572 0 : goto done;
5573 : }
5574 : else
5575 : {
5576 0 : CPLErrorReset();
5577 0 : ret = OGRERR_NONE;
5578 0 : continue;
5579 : }
5580 : }
5581 34 : if (z_geom->IsEmpty() ||
5582 17 : (!bKeepLowerDimGeom &&
5583 6 : (x_geom->getDimension() == y_geom->getDimension() &&
5584 6 : z_geom->getDimension() < x_geom->getDimension())))
5585 : {
5586 4 : continue;
5587 : }
5588 : }
5589 13 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5590 13 : z->SetFieldsFrom(x.get(), mapInput);
5591 13 : z->SetFieldsFrom(y.get(), mapMethod);
5592 13 : if (bPromoteToMulti)
5593 3 : z_geom.reset(promote_to_multi(z_geom.release()));
5594 13 : z->SetGeometryDirectly(z_geom.release());
5595 13 : ret = pLayerResult->CreateFeature(z.get());
5596 :
5597 13 : if (ret != OGRERR_NONE)
5598 : {
5599 0 : if (!bSkipFailures)
5600 : {
5601 0 : goto done;
5602 : }
5603 : else
5604 : {
5605 0 : CPLErrorReset();
5606 0 : ret = OGRERR_NONE;
5607 : }
5608 : }
5609 : }
5610 : }
5611 8 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5612 : {
5613 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5614 0 : ret = OGRERR_FAILURE;
5615 0 : goto done;
5616 : }
5617 8 : done:
5618 : // release resources
5619 8 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5620 8 : if (pGeometryMethodFilter)
5621 0 : delete pGeometryMethodFilter;
5622 8 : if (mapInput)
5623 4 : VSIFree(mapInput);
5624 8 : if (mapMethod)
5625 4 : VSIFree(mapMethod);
5626 8 : return ret;
5627 : }
5628 :
5629 : /************************************************************************/
5630 : /* OGR_L_Intersection() */
5631 : /************************************************************************/
5632 : /**
5633 : * \brief Intersection of two layers.
5634 : *
5635 : * The result layer contains features whose geometries represent areas
5636 : * that are common between features in the input layer and in the
5637 : * method layer. The features in the result layer have attributes from
5638 : * both input and method layers. The schema of the result layer can be
5639 : * set by the user or, if it is empty, is initialized to contain all
5640 : * fields in the input and method layers.
5641 : *
5642 : * \note If the schema of the result is set by user and contains
5643 : * fields that have the same name as a field in input and in method
5644 : * layer, then the attribute in the result feature will get the value
5645 : * from the feature of the method layer.
5646 : *
5647 : * \note For best performance use the minimum amount of features in
5648 : * the method layer and copy it into a memory layer.
5649 : *
5650 : * \note This method relies on GEOS support. Do not use unless the
5651 : * GEOS support is compiled in.
5652 : *
5653 : * The recognized list of options is :
5654 : * <ul>
5655 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5656 : * feature could not be inserted or a GEOS call failed.
5657 : * </li>
5658 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5659 : * into MultiPolygons, LineStrings to MultiLineStrings or
5660 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5661 : * </li>
5662 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5663 : * will be created from the fields of the input layer.
5664 : * </li>
5665 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5666 : * will be created from the fields of the method layer.
5667 : * </li>
5668 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
5669 : * geometries to pretest intersection of features of method layer
5670 : * with features of this layer.
5671 : * </li>
5672 : * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
5673 : * containment of features of method layer within the features of
5674 : * this layer. This will speed up the method significantly in some
5675 : * cases. Requires that the prepared geometries are in effect.
5676 : * </li>
5677 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
5678 : * result features with lower dimension geometry that would
5679 : * otherwise be added to the result layer. The default is YES, to add
5680 : * features with lower dimension geometry, but only if the result layer
5681 : * has an unknown geometry type.
5682 : * </li>
5683 : * </ul>
5684 : *
5685 : * This function is the same as the C++ method OGRLayer::Intersection().
5686 : *
5687 : * @param pLayerInput the input layer. Should not be NULL.
5688 : *
5689 : * @param pLayerMethod the method layer. Should not be NULL.
5690 : *
5691 : * @param pLayerResult the layer where the features resulting from the
5692 : * operation are inserted. Should not be NULL. See above the note
5693 : * about the schema.
5694 : *
5695 : * @param papszOptions NULL terminated list of options (may be NULL).
5696 : *
5697 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5698 : * reporting progress or NULL.
5699 : *
5700 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5701 : *
5702 : * @return an error code if there was an error or the execution was
5703 : * interrupted, OGRERR_NONE otherwise.
5704 : *
5705 : * @note The first geometry field is always used.
5706 : *
5707 : * @since OGR 1.10
5708 : */
5709 :
5710 7 : OGRErr OGR_L_Intersection(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5711 : OGRLayerH pLayerResult, CSLConstList papszOptions,
5712 : GDALProgressFunc pfnProgress, void *pProgressArg)
5713 :
5714 : {
5715 7 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE);
5716 7 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Intersection",
5717 : OGRERR_INVALID_HANDLE);
5718 7 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Intersection",
5719 : OGRERR_INVALID_HANDLE);
5720 :
5721 : return OGRLayer::FromHandle(pLayerInput)
5722 7 : ->Intersection(OGRLayer::FromHandle(pLayerMethod),
5723 : OGRLayer::FromHandle(pLayerResult), papszOptions,
5724 7 : pfnProgress, pProgressArg);
5725 : }
5726 :
5727 : /************************************************************************/
5728 : /* Union() */
5729 : /************************************************************************/
5730 :
5731 : /**
5732 : * \brief Union of two layers.
5733 : *
5734 : * The result layer contains features whose geometries represent areas
5735 : * that are either in the input layer, in the method layer, or in
5736 : * both. The features in the result layer have attributes from both
5737 : * input and method layers. For features which represent areas that
5738 : * are only in the input or in the method layer the respective
5739 : * attributes have undefined values. The schema of the result layer
5740 : * can be set by the user or, if it is empty, is initialized to
5741 : * contain all fields in the input and method layers.
5742 : *
5743 : * \note If the schema of the result is set by user and contains
5744 : * fields that have the same name as a field in input and in method
5745 : * layer, then the attribute in the result feature will get the value
5746 : * from the feature of the method layer (even if it is undefined).
5747 : *
5748 : * \note For best performance use the minimum amount of features in
5749 : * the method layer and copy it into a memory layer.
5750 : *
5751 : * \note This method relies on GEOS support. Do not use unless the
5752 : * GEOS support is compiled in.
5753 : *
5754 : * The recognized list of options is :
5755 : * <ul>
5756 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5757 : * feature could not be inserted or a GEOS call failed.
5758 : * </li>
5759 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5760 : * into MultiPolygons, LineStrings to MultiLineStrings or
5761 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5762 : * </li>
5763 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5764 : * will be created from the fields of the input layer.
5765 : * </li>
5766 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5767 : * will be created from the fields of the method layer.
5768 : * </li>
5769 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
5770 : * geometries to pretest intersection of features of method layer
5771 : * with features of this layer.
5772 : * </li>
5773 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
5774 : * result features with lower dimension geometry that would
5775 : * otherwise be added to the result layer. The default is YES, to add
5776 : * features with lower dimension geometry, but only if the result layer
5777 : * has an unknown geometry type.
5778 : * </li>
5779 : * </ul>
5780 : *
5781 : * This method is the same as the C function OGR_L_Union().
5782 : *
5783 : * @param pLayerMethod the method layer. Should not be NULL.
5784 : *
5785 : * @param pLayerResult the layer where the features resulting from the
5786 : * operation are inserted. Should not be NULL. See above the note
5787 : * about the schema.
5788 : *
5789 : * @param papszOptions NULL terminated list of options (may be NULL).
5790 : *
5791 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5792 : * reporting progress or NULL.
5793 : *
5794 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5795 : *
5796 : * @return an error code if there was an error or the execution was
5797 : * interrupted, OGRERR_NONE otherwise.
5798 : *
5799 : * @note The first geometry field is always used.
5800 : *
5801 : * @since OGR 1.10
5802 : */
5803 :
5804 18 : OGRErr OGRLayer::Union(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5805 : CSLConstList papszOptions, GDALProgressFunc pfnProgress,
5806 : void *pProgressArg)
5807 : {
5808 18 : OGRErr ret = OGRERR_NONE;
5809 18 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
5810 18 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
5811 18 : OGRFeatureDefn *poDefnResult = nullptr;
5812 18 : OGRGeometry *pGeometryMethodFilter = nullptr;
5813 18 : OGRGeometry *pGeometryInputFilter = nullptr;
5814 18 : int *mapInput = nullptr;
5815 18 : int *mapMethod = nullptr;
5816 : double progress_max =
5817 18 : static_cast<double>(GetFeatureCount(FALSE)) +
5818 18 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
5819 18 : double progress_counter = 0;
5820 18 : double progress_ticker = 0;
5821 : const bool bSkipFailures =
5822 18 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5823 18 : const bool bPromoteToMulti = CPLTestBool(
5824 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5825 18 : const bool bUsePreparedGeometries = CPLTestBool(
5826 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
5827 18 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
5828 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
5829 :
5830 : // check for GEOS
5831 18 : if (!OGRGeometryFactory::haveGEOS())
5832 : {
5833 0 : CPLError(CE_Failure, CPLE_AppDefined,
5834 : "OGRLayer::Union() requires GEOS support");
5835 0 : return OGRERR_UNSUPPORTED_OPERATION;
5836 : }
5837 :
5838 : // get resources
5839 18 : ret = clone_spatial_filter(this, &pGeometryInputFilter);
5840 18 : if (ret != OGRERR_NONE)
5841 0 : goto done;
5842 18 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5843 18 : if (ret != OGRERR_NONE)
5844 0 : goto done;
5845 18 : ret = create_field_map(poDefnInput, &mapInput);
5846 18 : if (ret != OGRERR_NONE)
5847 0 : goto done;
5848 18 : ret = create_field_map(poDefnMethod, &mapMethod);
5849 18 : if (ret != OGRERR_NONE)
5850 0 : goto done;
5851 18 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
5852 : mapMethod, true, papszOptions);
5853 18 : if (ret != OGRERR_NONE)
5854 0 : goto done;
5855 18 : poDefnResult = pLayerResult->GetLayerDefn();
5856 18 : if (bKeepLowerDimGeom)
5857 : {
5858 : // require that the result layer is of geom type unknown
5859 16 : if (pLayerResult->GetGeomType() != wkbUnknown)
5860 : {
5861 11 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
5862 : "since the result layer does not allow it.");
5863 11 : bKeepLowerDimGeom = FALSE;
5864 : }
5865 : }
5866 :
5867 : // add features based on input layer
5868 133 : for (auto &&x : this)
5869 : {
5870 :
5871 115 : if (pfnProgress)
5872 : {
5873 2 : double p = progress_counter / progress_max;
5874 2 : if (p > progress_ticker)
5875 : {
5876 1 : if (!pfnProgress(p, "", pProgressArg))
5877 : {
5878 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5879 0 : ret = OGRERR_FAILURE;
5880 0 : goto done;
5881 : }
5882 : }
5883 2 : progress_counter += 1.0;
5884 : }
5885 :
5886 : // set up the filter on method layer
5887 115 : CPLErrorReset();
5888 : OGRGeometry *x_geom =
5889 115 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5890 115 : if (CPLGetLastErrorType() != CE_None)
5891 : {
5892 0 : if (!bSkipFailures)
5893 : {
5894 0 : ret = OGRERR_FAILURE;
5895 0 : goto done;
5896 : }
5897 : else
5898 : {
5899 0 : CPLErrorReset();
5900 0 : ret = OGRERR_NONE;
5901 : }
5902 : }
5903 115 : if (!x_geom)
5904 : {
5905 0 : continue;
5906 : }
5907 :
5908 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
5909 115 : if (bUsePreparedGeometries)
5910 : {
5911 115 : x_prepared_geom.reset(
5912 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
5913 115 : if (!x_prepared_geom)
5914 : {
5915 0 : goto done;
5916 : }
5917 : }
5918 :
5919 : OGRGeometryUniquePtr x_geom_diff(
5920 : x_geom
5921 115 : ->clone()); // this will be the geometry of the result feature
5922 631 : for (auto &&y : pLayerMethod)
5923 : {
5924 516 : OGRGeometry *y_geom = y->GetGeometryRef();
5925 516 : if (!y_geom)
5926 : {
5927 0 : continue;
5928 : }
5929 :
5930 516 : CPLErrorReset();
5931 1032 : if (x_prepared_geom &&
5932 516 : !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
5933 516 : OGRGeometry::ToHandle(y_geom))))
5934 : {
5935 0 : if (CPLGetLastErrorType() == CE_None)
5936 : {
5937 0 : continue;
5938 : }
5939 : }
5940 516 : if (CPLGetLastErrorType() != CE_None)
5941 : {
5942 0 : if (!bSkipFailures)
5943 : {
5944 0 : ret = OGRERR_FAILURE;
5945 0 : goto done;
5946 : }
5947 : else
5948 : {
5949 0 : CPLErrorReset();
5950 0 : ret = OGRERR_NONE;
5951 : }
5952 : }
5953 :
5954 516 : CPLErrorReset();
5955 516 : OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
5956 516 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
5957 : {
5958 0 : if (!bSkipFailures)
5959 : {
5960 0 : ret = OGRERR_FAILURE;
5961 0 : goto done;
5962 : }
5963 : else
5964 : {
5965 0 : CPLErrorReset();
5966 0 : ret = OGRERR_NONE;
5967 0 : continue;
5968 : }
5969 : }
5970 1032 : if (poIntersection->IsEmpty() ||
5971 516 : (!bKeepLowerDimGeom &&
5972 507 : (x_geom->getDimension() == y_geom->getDimension() &&
5973 507 : poIntersection->getDimension() < x_geom->getDimension())))
5974 : {
5975 : // ok
5976 : }
5977 : else
5978 : {
5979 112 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5980 112 : z->SetFieldsFrom(x.get(), mapInput);
5981 112 : z->SetFieldsFrom(y.get(), mapMethod);
5982 112 : if (bPromoteToMulti)
5983 3 : poIntersection.reset(
5984 : promote_to_multi(poIntersection.release()));
5985 112 : z->SetGeometryDirectly(poIntersection.release());
5986 :
5987 112 : if (x_geom_diff)
5988 : {
5989 112 : CPLErrorReset();
5990 : OGRGeometryUniquePtr x_geom_diff_new(
5991 112 : x_geom_diff->Difference(y_geom));
5992 224 : if (CPLGetLastErrorType() != CE_None ||
5993 112 : x_geom_diff_new == nullptr)
5994 : {
5995 0 : if (!bSkipFailures)
5996 : {
5997 0 : ret = OGRERR_FAILURE;
5998 0 : goto done;
5999 : }
6000 : else
6001 : {
6002 0 : CPLErrorReset();
6003 : }
6004 : }
6005 : else
6006 : {
6007 112 : x_geom_diff.swap(x_geom_diff_new);
6008 : }
6009 : }
6010 :
6011 112 : ret = pLayerResult->CreateFeature(z.get());
6012 112 : if (ret != OGRERR_NONE)
6013 : {
6014 0 : if (!bSkipFailures)
6015 : {
6016 0 : goto done;
6017 : }
6018 : else
6019 : {
6020 0 : CPLErrorReset();
6021 0 : ret = OGRERR_NONE;
6022 : }
6023 : }
6024 : }
6025 : }
6026 115 : x_prepared_geom.reset();
6027 :
6028 115 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
6029 : {
6030 : // ok
6031 : }
6032 : else
6033 : {
6034 12 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6035 12 : z->SetFieldsFrom(x.get(), mapInput);
6036 12 : if (bPromoteToMulti)
6037 3 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
6038 12 : z->SetGeometryDirectly(x_geom_diff.release());
6039 12 : ret = pLayerResult->CreateFeature(z.get());
6040 12 : if (ret != OGRERR_NONE)
6041 : {
6042 0 : if (!bSkipFailures)
6043 : {
6044 0 : goto done;
6045 : }
6046 : else
6047 : {
6048 0 : CPLErrorReset();
6049 0 : ret = OGRERR_NONE;
6050 : }
6051 : }
6052 : }
6053 : }
6054 :
6055 : // restore filter on method layer and add features based on it
6056 18 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
6057 130 : for (auto &&x : pLayerMethod)
6058 : {
6059 :
6060 112 : if (pfnProgress)
6061 : {
6062 1 : double p = progress_counter / progress_max;
6063 1 : if (p > progress_ticker)
6064 : {
6065 1 : if (!pfnProgress(p, "", pProgressArg))
6066 : {
6067 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6068 0 : ret = OGRERR_FAILURE;
6069 0 : goto done;
6070 : }
6071 : }
6072 1 : progress_counter += 1.0;
6073 : }
6074 :
6075 : // set up the filter on input layer
6076 112 : CPLErrorReset();
6077 : OGRGeometry *x_geom =
6078 112 : set_filter_from(this, pGeometryInputFilter, x.get());
6079 112 : if (CPLGetLastErrorType() != CE_None)
6080 : {
6081 0 : if (!bSkipFailures)
6082 : {
6083 0 : ret = OGRERR_FAILURE;
6084 0 : goto done;
6085 : }
6086 : else
6087 : {
6088 0 : CPLErrorReset();
6089 0 : ret = OGRERR_NONE;
6090 : }
6091 : }
6092 112 : if (!x_geom)
6093 : {
6094 0 : continue;
6095 : }
6096 :
6097 : OGRGeometryUniquePtr x_geom_diff(
6098 : x_geom
6099 112 : ->clone()); // this will be the geometry of the result feature
6100 628 : for (auto &&y : this)
6101 : {
6102 516 : OGRGeometry *y_geom = y->GetGeometryRef();
6103 516 : if (!y_geom)
6104 : {
6105 0 : continue;
6106 : }
6107 :
6108 516 : if (x_geom_diff)
6109 : {
6110 516 : CPLErrorReset();
6111 : OGRGeometryUniquePtr x_geom_diff_new(
6112 516 : x_geom_diff->Difference(y_geom));
6113 1032 : if (CPLGetLastErrorType() != CE_None ||
6114 516 : x_geom_diff_new == nullptr)
6115 : {
6116 0 : if (!bSkipFailures)
6117 : {
6118 0 : ret = OGRERR_FAILURE;
6119 0 : goto done;
6120 : }
6121 : else
6122 : {
6123 0 : CPLErrorReset();
6124 0 : ret = OGRERR_NONE;
6125 : }
6126 : }
6127 : else
6128 : {
6129 516 : x_geom_diff.swap(x_geom_diff_new);
6130 : }
6131 : }
6132 : }
6133 :
6134 112 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
6135 : {
6136 : // ok
6137 : }
6138 : else
6139 : {
6140 8 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6141 8 : z->SetFieldsFrom(x.get(), mapMethod);
6142 8 : if (bPromoteToMulti)
6143 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
6144 8 : z->SetGeometryDirectly(x_geom_diff.release());
6145 8 : ret = pLayerResult->CreateFeature(z.get());
6146 8 : if (ret != OGRERR_NONE)
6147 : {
6148 0 : if (!bSkipFailures)
6149 : {
6150 0 : goto done;
6151 : }
6152 : else
6153 : {
6154 0 : CPLErrorReset();
6155 0 : ret = OGRERR_NONE;
6156 : }
6157 : }
6158 : }
6159 : }
6160 18 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
6161 : {
6162 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6163 0 : ret = OGRERR_FAILURE;
6164 0 : goto done;
6165 : }
6166 18 : done:
6167 : // release resources
6168 18 : SetSpatialFilter(pGeometryInputFilter);
6169 18 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
6170 18 : if (pGeometryMethodFilter)
6171 0 : delete pGeometryMethodFilter;
6172 18 : if (pGeometryInputFilter)
6173 0 : delete pGeometryInputFilter;
6174 18 : if (mapInput)
6175 15 : VSIFree(mapInput);
6176 18 : if (mapMethod)
6177 14 : VSIFree(mapMethod);
6178 18 : return ret;
6179 : }
6180 :
6181 : /************************************************************************/
6182 : /* OGR_L_Union() */
6183 : /************************************************************************/
6184 :
6185 : /**
6186 : * \brief Union of two layers.
6187 : *
6188 : * The result layer contains features whose geometries represent areas
6189 : * that are in either in the input layer, in the method layer, or in
6190 : * both. The features in the result layer have attributes from both
6191 : * input and method layers. For features which represent areas that
6192 : * are only in the input or in the method layer the respective
6193 : * attributes have undefined values. The schema of the result layer
6194 : * can be set by the user or, if it is empty, is initialized to
6195 : * contain all fields in the input and method layers.
6196 : *
6197 : * \note If the schema of the result is set by user and contains
6198 : * fields that have the same name as a field in input and in method
6199 : * layer, then the attribute in the result feature will get the value
6200 : * from the feature of the method layer (even if it is undefined).
6201 : *
6202 : * \note For best performance use the minimum amount of features in
6203 : * the method layer and copy it into a memory layer.
6204 : *
6205 : * \note This method relies on GEOS support. Do not use unless the
6206 : * GEOS support is compiled in.
6207 : *
6208 : * The recognized list of options is :
6209 : * <ul>
6210 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6211 : * feature could not be inserted or a GEOS call failed.
6212 : * </li>
6213 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
6214 : * into MultiPolygons, LineStrings to MultiLineStrings or
6215 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
6216 : * </li>
6217 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6218 : * will be created from the fields of the input layer.
6219 : * </li>
6220 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6221 : * will be created from the fields of the method layer.
6222 : * </li>
6223 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
6224 : * geometries to pretest intersection of features of method layer
6225 : * with features of this layer.
6226 : * </li>
6227 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
6228 : * result features with lower dimension geometry that would
6229 : * otherwise be added to the result layer. The default is YES, to add
6230 : * features with lower dimension geometry, but only if the result layer
6231 : * has an unknown geometry type.
6232 : * </li>
6233 : * </ul>
6234 : *
6235 : * This function is the same as the C++ method OGRLayer::Union().
6236 : *
6237 : * @param pLayerInput the input layer. Should not be NULL.
6238 : *
6239 : * @param pLayerMethod the method layer. Should not be NULL.
6240 : *
6241 : * @param pLayerResult the layer where the features resulting from the
6242 : * operation are inserted. Should not be NULL. See above the note
6243 : * about the schema.
6244 : *
6245 : * @param papszOptions NULL terminated list of options (may be NULL).
6246 : *
6247 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
6248 : * reporting progress or NULL.
6249 : *
6250 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6251 : *
6252 : * @return an error code if there was an error or the execution was
6253 : * interrupted, OGRERR_NONE otherwise.
6254 : *
6255 : * @note The first geometry field is always used.
6256 : *
6257 : * @since OGR 1.10
6258 : */
6259 :
6260 7 : OGRErr OGR_L_Union(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
6261 : OGRLayerH pLayerResult, CSLConstList papszOptions,
6262 : GDALProgressFunc pfnProgress, void *pProgressArg)
6263 :
6264 : {
6265 7 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE);
6266 7 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE);
6267 7 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE);
6268 :
6269 : return OGRLayer::FromHandle(pLayerInput)
6270 7 : ->Union(OGRLayer::FromHandle(pLayerMethod),
6271 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
6272 7 : pProgressArg);
6273 : }
6274 :
6275 : /************************************************************************/
6276 : /* SymDifference() */
6277 : /************************************************************************/
6278 :
6279 : /**
6280 : * \brief Symmetrical difference of two layers.
6281 : *
6282 : * The result layer contains features whose geometries represent areas
6283 : * that are in either in the input layer or in the method layer but
6284 : * not in both. The features in the result layer have attributes from
6285 : * both input and method layers. For features which represent areas
6286 : * that are only in the input or in the method layer the respective
6287 : * attributes have undefined values. The schema of the result layer
6288 : * can be set by the user or, if it is empty, is initialized to
6289 : * contain all fields in the input and method layers.
6290 : *
6291 : * \note If the schema of the result is set by user and contains
6292 : * fields that have the same name as a field in input and in method
6293 : * layer, then the attribute in the result feature will get the value
6294 : * from the feature of the method layer (even if it is undefined).
6295 : *
6296 : * \note For best performance use the minimum amount of features in
6297 : * the method layer and copy it into a memory layer.
6298 : *
6299 : * \note This method relies on GEOS support. Do not use unless the
6300 : * GEOS support is compiled in.
6301 : *
6302 : * The recognized list of options is :
6303 : * <ul>
6304 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6305 : * feature could not be inserted or a GEOS call failed.
6306 : * </li>
6307 : * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
6308 : * into MultiPolygons, or LineStrings to MultiLineStrings.
6309 : * </li>
6310 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6311 : * will be created from the fields of the input layer.
6312 : * </li>
6313 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6314 : * will be created from the fields of the method layer.
6315 : * </li>
6316 : * </ul>
6317 : *
6318 : * This method is the same as the C function OGR_L_SymDifference().
6319 : *
6320 : * @param pLayerMethod the method layer. Should not be NULL.
6321 : *
6322 : * @param pLayerResult the layer where the features resulting from the
6323 : * operation are inserted. Should not be NULL. See above the note
6324 : * about the schema.
6325 : *
6326 : * @param papszOptions NULL terminated list of options (may be NULL).
6327 : *
6328 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
6329 : * reporting progress or NULL.
6330 : *
6331 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6332 : *
6333 : * @return an error code if there was an error or the execution was
6334 : * interrupted, OGRERR_NONE otherwise.
6335 : *
6336 : * @note The first geometry field is always used.
6337 : *
6338 : * @since OGR 1.10
6339 : */
6340 :
6341 5 : OGRErr OGRLayer::SymDifference(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
6342 : CSLConstList papszOptions,
6343 : GDALProgressFunc pfnProgress, void *pProgressArg)
6344 : {
6345 5 : OGRErr ret = OGRERR_NONE;
6346 5 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
6347 5 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
6348 5 : OGRFeatureDefn *poDefnResult = nullptr;
6349 5 : OGRGeometry *pGeometryMethodFilter = nullptr;
6350 5 : OGRGeometry *pGeometryInputFilter = nullptr;
6351 5 : int *mapInput = nullptr;
6352 5 : int *mapMethod = nullptr;
6353 : double progress_max =
6354 5 : static_cast<double>(GetFeatureCount(FALSE)) +
6355 5 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
6356 5 : double progress_counter = 0;
6357 5 : double progress_ticker = 0;
6358 : const bool bSkipFailures =
6359 5 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
6360 5 : const bool bPromoteToMulti = CPLTestBool(
6361 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
6362 :
6363 : // check for GEOS
6364 5 : if (!OGRGeometryFactory::haveGEOS())
6365 : {
6366 0 : CPLError(CE_Failure, CPLE_AppDefined,
6367 : "OGRLayer::SymDifference() requires GEOS support");
6368 0 : return OGRERR_UNSUPPORTED_OPERATION;
6369 : }
6370 :
6371 : // get resources
6372 5 : ret = clone_spatial_filter(this, &pGeometryInputFilter);
6373 5 : if (ret != OGRERR_NONE)
6374 0 : goto done;
6375 5 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
6376 5 : if (ret != OGRERR_NONE)
6377 0 : goto done;
6378 5 : ret = create_field_map(poDefnInput, &mapInput);
6379 5 : if (ret != OGRERR_NONE)
6380 0 : goto done;
6381 5 : ret = create_field_map(poDefnMethod, &mapMethod);
6382 5 : if (ret != OGRERR_NONE)
6383 0 : goto done;
6384 5 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
6385 : mapMethod, true, papszOptions);
6386 5 : if (ret != OGRERR_NONE)
6387 0 : goto done;
6388 5 : poDefnResult = pLayerResult->GetLayerDefn();
6389 :
6390 : // add features based on input layer
6391 15 : for (auto &&x : this)
6392 : {
6393 :
6394 10 : if (pfnProgress)
6395 : {
6396 2 : double p = progress_counter / progress_max;
6397 2 : if (p > progress_ticker)
6398 : {
6399 1 : if (!pfnProgress(p, "", pProgressArg))
6400 : {
6401 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6402 0 : ret = OGRERR_FAILURE;
6403 0 : goto done;
6404 : }
6405 : }
6406 2 : progress_counter += 1.0;
6407 : }
6408 :
6409 : // set up the filter on method layer
6410 10 : CPLErrorReset();
6411 : OGRGeometry *x_geom =
6412 10 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
6413 10 : if (CPLGetLastErrorType() != CE_None)
6414 : {
6415 0 : if (!bSkipFailures)
6416 : {
6417 0 : ret = OGRERR_FAILURE;
6418 0 : goto done;
6419 : }
6420 : else
6421 : {
6422 0 : CPLErrorReset();
6423 0 : ret = OGRERR_NONE;
6424 : }
6425 : }
6426 10 : if (!x_geom)
6427 : {
6428 0 : continue;
6429 : }
6430 :
6431 : OGRGeometryUniquePtr geom(
6432 : x_geom
6433 10 : ->clone()); // this will be the geometry of the result feature
6434 18 : for (auto &&y : pLayerMethod)
6435 : {
6436 11 : OGRGeometry *y_geom = y->GetGeometryRef();
6437 11 : if (!y_geom)
6438 : {
6439 0 : continue;
6440 : }
6441 11 : if (geom)
6442 : {
6443 11 : CPLErrorReset();
6444 11 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
6445 11 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
6446 : {
6447 0 : if (!bSkipFailures)
6448 : {
6449 0 : ret = OGRERR_FAILURE;
6450 0 : goto done;
6451 : }
6452 : else
6453 : {
6454 0 : CPLErrorReset();
6455 0 : ret = OGRERR_NONE;
6456 : }
6457 : }
6458 : else
6459 : {
6460 11 : geom.swap(geom_new);
6461 : }
6462 : }
6463 11 : if (geom && geom->IsEmpty())
6464 3 : break;
6465 : }
6466 :
6467 10 : if (geom && !geom->IsEmpty())
6468 : {
6469 7 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6470 7 : z->SetFieldsFrom(x.get(), mapInput);
6471 7 : if (bPromoteToMulti)
6472 2 : geom.reset(promote_to_multi(geom.release()));
6473 7 : z->SetGeometryDirectly(geom.release());
6474 7 : ret = pLayerResult->CreateFeature(z.get());
6475 7 : if (ret != OGRERR_NONE)
6476 : {
6477 0 : if (!bSkipFailures)
6478 : {
6479 0 : goto done;
6480 : }
6481 : else
6482 : {
6483 0 : CPLErrorReset();
6484 0 : ret = OGRERR_NONE;
6485 : }
6486 : }
6487 : }
6488 : }
6489 :
6490 : // restore filter on method layer and add features based on it
6491 5 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
6492 14 : for (auto &&x : pLayerMethod)
6493 : {
6494 :
6495 9 : if (pfnProgress)
6496 : {
6497 2 : double p = progress_counter / progress_max;
6498 2 : if (p > progress_ticker)
6499 : {
6500 2 : if (!pfnProgress(p, "", pProgressArg))
6501 : {
6502 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6503 0 : ret = OGRERR_FAILURE;
6504 0 : goto done;
6505 : }
6506 : }
6507 2 : progress_counter += 1.0;
6508 : }
6509 :
6510 : // set up the filter on input layer
6511 9 : CPLErrorReset();
6512 : OGRGeometry *x_geom =
6513 9 : set_filter_from(this, pGeometryInputFilter, x.get());
6514 9 : if (CPLGetLastErrorType() != CE_None)
6515 : {
6516 0 : if (!bSkipFailures)
6517 : {
6518 0 : ret = OGRERR_FAILURE;
6519 0 : goto done;
6520 : }
6521 : else
6522 : {
6523 0 : CPLErrorReset();
6524 0 : ret = OGRERR_NONE;
6525 : }
6526 : }
6527 9 : if (!x_geom)
6528 : {
6529 0 : continue;
6530 : }
6531 :
6532 : OGRGeometryUniquePtr geom(
6533 : x_geom
6534 9 : ->clone()); // this will be the geometry of the result feature
6535 17 : for (auto &&y : this)
6536 : {
6537 11 : OGRGeometry *y_geom = y->GetGeometryRef();
6538 11 : if (!y_geom)
6539 0 : continue;
6540 11 : if (geom)
6541 : {
6542 11 : CPLErrorReset();
6543 11 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
6544 11 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
6545 : {
6546 0 : if (!bSkipFailures)
6547 : {
6548 0 : ret = OGRERR_FAILURE;
6549 0 : goto done;
6550 : }
6551 : else
6552 : {
6553 0 : CPLErrorReset();
6554 0 : ret = OGRERR_NONE;
6555 : }
6556 : }
6557 : else
6558 : {
6559 11 : geom.swap(geom_new);
6560 : }
6561 : }
6562 11 : if (geom == nullptr || geom->IsEmpty())
6563 3 : break;
6564 : }
6565 :
6566 9 : if (geom && !geom->IsEmpty())
6567 : {
6568 6 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6569 6 : z->SetFieldsFrom(x.get(), mapMethod);
6570 6 : if (bPromoteToMulti)
6571 1 : geom.reset(promote_to_multi(geom.release()));
6572 6 : z->SetGeometryDirectly(geom.release());
6573 6 : ret = pLayerResult->CreateFeature(z.get());
6574 6 : if (ret != OGRERR_NONE)
6575 : {
6576 0 : if (!bSkipFailures)
6577 : {
6578 0 : goto done;
6579 : }
6580 : else
6581 : {
6582 0 : CPLErrorReset();
6583 0 : ret = OGRERR_NONE;
6584 : }
6585 : }
6586 : }
6587 : }
6588 5 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
6589 : {
6590 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6591 0 : ret = OGRERR_FAILURE;
6592 0 : goto done;
6593 : }
6594 5 : done:
6595 : // release resources
6596 5 : SetSpatialFilter(pGeometryInputFilter);
6597 5 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
6598 5 : if (pGeometryMethodFilter)
6599 0 : delete pGeometryMethodFilter;
6600 5 : if (pGeometryInputFilter)
6601 0 : delete pGeometryInputFilter;
6602 5 : if (mapInput)
6603 4 : VSIFree(mapInput);
6604 5 : if (mapMethod)
6605 4 : VSIFree(mapMethod);
6606 5 : return ret;
6607 : }
6608 :
6609 : /************************************************************************/
6610 : /* OGR_L_SymDifference() */
6611 : /************************************************************************/
6612 :
6613 : /**
6614 : * \brief Symmetrical difference of two layers.
6615 : *
6616 : * The result layer contains features whose geometries represent areas
6617 : * that are in either in the input layer or in the method layer but
6618 : * not in both. The features in the result layer have attributes from
6619 : * both input and method layers. For features which represent areas
6620 : * that are only in the input or in the method layer the respective
6621 : * attributes have undefined values. The schema of the result layer
6622 : * can be set by the user or, if it is empty, is initialized to
6623 : * contain all fields in the input and method layers.
6624 : *
6625 : * \note If the schema of the result is set by user and contains
6626 : * fields that have the same name as a field in input and in method
6627 : * layer, then the attribute in the result feature will get the value
6628 : * from the feature of the method layer (even if it is undefined).
6629 : *
6630 : * \note For best performance use the minimum amount of features in
6631 : * the method layer and copy it into a memory layer.
6632 : *
6633 : * \note This method relies on GEOS support. Do not use unless the
6634 : * GEOS support is compiled in.
6635 : *
6636 : * The recognized list of options is :
6637 : * <ul>
6638 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6639 : * feature could not be inserted or a GEOS call failed.
6640 : * </li>
6641 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
6642 : * into MultiPolygons, LineStrings to MultiLineStrings or
6643 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
6644 : * </li>
6645 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6646 : * will be created from the fields of the input layer.
6647 : * </li>
6648 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6649 : * will be created from the fields of the method layer.
6650 : * </li>
6651 : * </ul>
6652 : *
6653 : * This function is the same as the C++ method OGRLayer::SymDifference().
6654 : *
6655 : * @param pLayerInput the input layer. Should not be NULL.
6656 : *
6657 : * @param pLayerMethod the method layer. Should not be NULL.
6658 : *
6659 : * @param pLayerResult the layer where the features resulting from the
6660 : * operation are inserted. Should not be NULL. See above the note
6661 : * about the schema.
6662 : *
6663 : * @param papszOptions NULL terminated list of options (may be NULL).
6664 : *
6665 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
6666 : * reporting progress or NULL.
6667 : *
6668 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6669 : *
6670 : * @return an error code if there was an error or the execution was
6671 : * interrupted, OGRERR_NONE otherwise.
6672 : *
6673 : * @note The first geometry field is always used.
6674 : *
6675 : * @since OGR 1.10
6676 : */
6677 :
6678 4 : OGRErr OGR_L_SymDifference(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
6679 : OGRLayerH pLayerResult, CSLConstList papszOptions,
6680 : GDALProgressFunc pfnProgress, void *pProgressArg)
6681 :
6682 : {
6683 4 : VALIDATE_POINTER1(pLayerInput, "OGR_L_SymDifference",
6684 : OGRERR_INVALID_HANDLE);
6685 4 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_SymDifference",
6686 : OGRERR_INVALID_HANDLE);
6687 4 : VALIDATE_POINTER1(pLayerResult, "OGR_L_SymDifference",
6688 : OGRERR_INVALID_HANDLE);
6689 :
6690 : return OGRLayer::FromHandle(pLayerInput)
6691 4 : ->SymDifference(OGRLayer::FromHandle(pLayerMethod),
6692 : OGRLayer::FromHandle(pLayerResult), papszOptions,
6693 4 : pfnProgress, pProgressArg);
6694 : }
6695 :
6696 : /************************************************************************/
6697 : /* Identity() */
6698 : /************************************************************************/
6699 :
6700 : /**
6701 : * \brief Identify the features of this layer with the ones from the
6702 : * identity layer.
6703 : *
6704 : * The result layer contains features whose geometries represent areas
6705 : * that are in the input layer. The features in the result layer have
6706 : * attributes from both input and method layers. The schema of the
6707 : * result layer can be set by the user or, if it is empty, is
6708 : * initialized to contain all fields in input and method layers.
6709 : *
6710 : * \note If the schema of the result is set by user and contains
6711 : * fields that have the same name as a field in input and in method
6712 : * layer, then the attribute in the result feature will get the value
6713 : * from the feature of the method layer (even if it is undefined).
6714 : *
6715 : * \note For best performance use the minimum amount of features in
6716 : * the method layer and copy it into a memory layer.
6717 : *
6718 : * \note This method relies on GEOS support. Do not use unless the
6719 : * GEOS support is compiled in.
6720 : *
6721 : * The recognized list of options is :
6722 : * <ul>
6723 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
6724 : * feature could not be inserted or a GEOS call failed.
6725 : * </li>
6726 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
6727 : * into MultiPolygons, LineStrings to MultiLineStrings or
6728 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
6729 : * </li>
6730 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
6731 : * will be created from the fields of the input layer.
6732 : * </li>
6733 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
6734 : * will be created from the fields of the method layer.
6735 : * </li>
6736 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
6737 : * geometries to pretest intersection of features of method layer
6738 : * with features of this layer.
6739 : * </li>
6740 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
6741 : * result features with lower dimension geometry that would
6742 : * otherwise be added to the result layer. The default is YES, to add
6743 : * features with lower dimension geometry, but only if the result layer
6744 : * has an unknown geometry type.
6745 : * </li>
6746 : * </ul>
6747 : *
6748 : * This method is the same as the C function OGR_L_Identity().
6749 : *
6750 : * @param pLayerMethod the method layer. Should not be NULL.
6751 : *
6752 : * @param pLayerResult the layer where the features resulting from the
6753 : * operation are inserted. Should not be NULL. See above the note
6754 : * about the schema.
6755 : *
6756 : * @param papszOptions NULL terminated list of options (may be NULL).
6757 : *
6758 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
6759 : * reporting progress or NULL.
6760 : *
6761 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6762 : *
6763 : * @return an error code if there was an error or the execution was
6764 : * interrupted, OGRERR_NONE otherwise.
6765 : *
6766 : * @note The first geometry field is always used.
6767 : *
6768 : * @since OGR 1.10
6769 : */
6770 :
6771 7 : OGRErr OGRLayer::Identity(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
6772 : CSLConstList papszOptions,
6773 : GDALProgressFunc pfnProgress, void *pProgressArg)
6774 : {
6775 7 : OGRErr ret = OGRERR_NONE;
6776 7 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
6777 7 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
6778 7 : OGRFeatureDefn *poDefnResult = nullptr;
6779 7 : OGRGeometry *pGeometryMethodFilter = nullptr;
6780 7 : int *mapInput = nullptr;
6781 7 : int *mapMethod = nullptr;
6782 7 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
6783 7 : double progress_counter = 0;
6784 7 : double progress_ticker = 0;
6785 : const bool bSkipFailures =
6786 7 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
6787 7 : const bool bPromoteToMulti = CPLTestBool(
6788 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
6789 7 : const bool bUsePreparedGeometries = CPLTestBool(
6790 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
6791 7 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
6792 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
6793 :
6794 : // check for GEOS
6795 7 : if (!OGRGeometryFactory::haveGEOS())
6796 : {
6797 0 : CPLError(CE_Failure, CPLE_AppDefined,
6798 : "OGRLayer::Identity() requires GEOS support");
6799 0 : return OGRERR_UNSUPPORTED_OPERATION;
6800 : }
6801 7 : if (bKeepLowerDimGeom)
6802 : {
6803 : // require that the result layer is of geom type unknown
6804 5 : if (pLayerResult->GetGeomType() != wkbUnknown)
6805 : {
6806 0 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
6807 : "since the result layer does not allow it.");
6808 0 : bKeepLowerDimGeom = FALSE;
6809 : }
6810 : }
6811 :
6812 : // get resources
6813 7 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
6814 7 : if (ret != OGRERR_NONE)
6815 0 : goto done;
6816 7 : ret = create_field_map(poDefnInput, &mapInput);
6817 7 : if (ret != OGRERR_NONE)
6818 0 : goto done;
6819 7 : ret = create_field_map(poDefnMethod, &mapMethod);
6820 7 : if (ret != OGRERR_NONE)
6821 0 : goto done;
6822 7 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
6823 : mapMethod, true, papszOptions);
6824 7 : if (ret != OGRERR_NONE)
6825 0 : goto done;
6826 7 : poDefnResult = pLayerResult->GetLayerDefn();
6827 :
6828 : // split the features in input layer to the result layer
6829 21 : for (auto &&x : this)
6830 : {
6831 :
6832 14 : if (pfnProgress)
6833 : {
6834 2 : double p = progress_counter / progress_max;
6835 2 : if (p > progress_ticker)
6836 : {
6837 1 : if (!pfnProgress(p, "", pProgressArg))
6838 : {
6839 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
6840 0 : ret = OGRERR_FAILURE;
6841 0 : goto done;
6842 : }
6843 : }
6844 2 : progress_counter += 1.0;
6845 : }
6846 :
6847 : // set up the filter on method layer
6848 14 : CPLErrorReset();
6849 : OGRGeometry *x_geom =
6850 14 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
6851 14 : if (CPLGetLastErrorType() != CE_None)
6852 : {
6853 0 : if (!bSkipFailures)
6854 : {
6855 0 : ret = OGRERR_FAILURE;
6856 0 : goto done;
6857 : }
6858 : else
6859 : {
6860 0 : CPLErrorReset();
6861 0 : ret = OGRERR_NONE;
6862 : }
6863 : }
6864 14 : if (!x_geom)
6865 : {
6866 0 : continue;
6867 : }
6868 :
6869 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
6870 14 : if (bUsePreparedGeometries)
6871 : {
6872 14 : x_prepared_geom.reset(
6873 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
6874 14 : if (!x_prepared_geom)
6875 : {
6876 0 : goto done;
6877 : }
6878 : }
6879 :
6880 : OGRGeometryUniquePtr x_geom_diff(
6881 : x_geom
6882 14 : ->clone()); // this will be the geometry of the result feature
6883 30 : for (auto &&y : pLayerMethod)
6884 : {
6885 16 : OGRGeometry *y_geom = y->GetGeometryRef();
6886 16 : if (!y_geom)
6887 0 : continue;
6888 :
6889 16 : CPLErrorReset();
6890 32 : if (x_prepared_geom &&
6891 16 : !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
6892 16 : OGRGeometry::ToHandle(y_geom))))
6893 : {
6894 0 : if (CPLGetLastErrorType() == CE_None)
6895 : {
6896 0 : continue;
6897 : }
6898 : }
6899 16 : if (CPLGetLastErrorType() != CE_None)
6900 : {
6901 0 : if (!bSkipFailures)
6902 : {
6903 0 : ret = OGRERR_FAILURE;
6904 0 : goto done;
6905 : }
6906 : else
6907 : {
6908 0 : CPLErrorReset();
6909 0 : ret = OGRERR_NONE;
6910 : }
6911 : }
6912 :
6913 16 : CPLErrorReset();
6914 16 : OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
6915 16 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
6916 : {
6917 0 : if (!bSkipFailures)
6918 : {
6919 0 : ret = OGRERR_FAILURE;
6920 0 : goto done;
6921 : }
6922 : else
6923 : {
6924 0 : CPLErrorReset();
6925 0 : ret = OGRERR_NONE;
6926 : }
6927 : }
6928 32 : else if (poIntersection->IsEmpty() ||
6929 16 : (!bKeepLowerDimGeom &&
6930 6 : (x_geom->getDimension() == y_geom->getDimension() &&
6931 6 : poIntersection->getDimension() <
6932 6 : x_geom->getDimension())))
6933 : {
6934 : /* ok*/
6935 : }
6936 : else
6937 : {
6938 12 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6939 12 : z->SetFieldsFrom(x.get(), mapInput);
6940 12 : z->SetFieldsFrom(y.get(), mapMethod);
6941 12 : if (bPromoteToMulti)
6942 2 : poIntersection.reset(
6943 : promote_to_multi(poIntersection.release()));
6944 12 : z->SetGeometryDirectly(poIntersection.release());
6945 12 : if (x_geom_diff)
6946 : {
6947 12 : CPLErrorReset();
6948 : OGRGeometryUniquePtr x_geom_diff_new(
6949 12 : x_geom_diff->Difference(y_geom));
6950 24 : if (CPLGetLastErrorType() != CE_None ||
6951 12 : x_geom_diff_new == nullptr)
6952 : {
6953 0 : if (!bSkipFailures)
6954 : {
6955 0 : ret = OGRERR_FAILURE;
6956 0 : goto done;
6957 : }
6958 : else
6959 : {
6960 0 : CPLErrorReset();
6961 : }
6962 : }
6963 : else
6964 : {
6965 12 : x_geom_diff.swap(x_geom_diff_new);
6966 : }
6967 : }
6968 12 : ret = pLayerResult->CreateFeature(z.get());
6969 12 : if (ret != OGRERR_NONE)
6970 : {
6971 0 : if (!bSkipFailures)
6972 : {
6973 0 : goto done;
6974 : }
6975 : else
6976 : {
6977 0 : CPLErrorReset();
6978 0 : ret = OGRERR_NONE;
6979 : }
6980 : }
6981 : }
6982 : }
6983 :
6984 14 : x_prepared_geom.reset();
6985 :
6986 14 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
6987 : {
6988 : /* ok */
6989 : }
6990 : else
6991 : {
6992 11 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
6993 11 : z->SetFieldsFrom(x.get(), mapInput);
6994 11 : if (bPromoteToMulti)
6995 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
6996 11 : z->SetGeometryDirectly(x_geom_diff.release());
6997 11 : ret = pLayerResult->CreateFeature(z.get());
6998 11 : if (ret != OGRERR_NONE)
6999 : {
7000 0 : if (!bSkipFailures)
7001 : {
7002 0 : goto done;
7003 : }
7004 : else
7005 : {
7006 0 : CPLErrorReset();
7007 0 : ret = OGRERR_NONE;
7008 : }
7009 : }
7010 : }
7011 : }
7012 7 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
7013 : {
7014 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7015 0 : ret = OGRERR_FAILURE;
7016 0 : goto done;
7017 : }
7018 7 : done:
7019 : // release resources
7020 7 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
7021 7 : if (pGeometryMethodFilter)
7022 0 : delete pGeometryMethodFilter;
7023 7 : if (mapInput)
7024 4 : VSIFree(mapInput);
7025 7 : if (mapMethod)
7026 4 : VSIFree(mapMethod);
7027 7 : return ret;
7028 : }
7029 :
7030 : /************************************************************************/
7031 : /* OGR_L_Identity() */
7032 : /************************************************************************/
7033 :
7034 : /**
7035 : * \brief Identify the features of this layer with the ones from the
7036 : * identity layer.
7037 : *
7038 : * The result layer contains features whose geometries represent areas
7039 : * that are in the input layer. The features in the result layer have
7040 : * attributes from both input and method layers. The schema of the
7041 : * result layer can be set by the user or, if it is empty, is
7042 : * initialized to contain all fields in input and method layers.
7043 : *
7044 : * \note If the schema of the result is set by user and contains
7045 : * fields that have the same name as a field in input and in method
7046 : * layer, then the attribute in the result feature will get the value
7047 : * from the feature of the method layer (even if it is undefined).
7048 : *
7049 : * \note For best performance use the minimum amount of features in
7050 : * the method layer and copy it into a memory layer.
7051 : *
7052 : * \note This method relies on GEOS support. Do not use unless the
7053 : * GEOS support is compiled in.
7054 : *
7055 : * The recognized list of options is :
7056 : * <ul>
7057 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7058 : * feature could not be inserted or a GEOS call failed.
7059 : * </li>
7060 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7061 : * into MultiPolygons, LineStrings to MultiLineStrings or
7062 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
7063 : * </li>
7064 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7065 : * will be created from the fields of the input layer.
7066 : * </li>
7067 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7068 : * will be created from the fields of the method layer.
7069 : * </li>
7070 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
7071 : * geometries to pretest intersection of features of method layer
7072 : * with features of this layer.
7073 : * </li>
7074 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
7075 : * result features with lower dimension geometry that would
7076 : * otherwise be added to the result layer. The default is YES, to add
7077 : * features with lower dimension geometry, but only if the result layer
7078 : * has an unknown geometry type.
7079 : * </li>
7080 : * </ul>
7081 : *
7082 : * This function is the same as the C++ method OGRLayer::Identity().
7083 : *
7084 : * @param pLayerInput the input layer. Should not be NULL.
7085 : *
7086 : * @param pLayerMethod the method layer. Should not be NULL.
7087 : *
7088 : * @param pLayerResult the layer where the features resulting from the
7089 : * operation are inserted. Should not be NULL. See above the note
7090 : * about the schema.
7091 : *
7092 : * @param papszOptions NULL terminated list of options (may be NULL).
7093 : *
7094 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
7095 : * reporting progress or NULL.
7096 : *
7097 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7098 : *
7099 : * @return an error code if there was an error or the execution was
7100 : * interrupted, OGRERR_NONE otherwise.
7101 : *
7102 : * @note The first geometry field is always used.
7103 : *
7104 : * @since OGR 1.10
7105 : */
7106 :
7107 6 : OGRErr OGR_L_Identity(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
7108 : OGRLayerH pLayerResult, CSLConstList papszOptions,
7109 : GDALProgressFunc pfnProgress, void *pProgressArg)
7110 :
7111 : {
7112 6 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
7113 6 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
7114 6 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
7115 :
7116 : return OGRLayer::FromHandle(pLayerInput)
7117 6 : ->Identity(OGRLayer::FromHandle(pLayerMethod),
7118 : OGRLayer::FromHandle(pLayerResult), papszOptions,
7119 6 : pfnProgress, pProgressArg);
7120 : }
7121 :
7122 : /************************************************************************/
7123 : /* Update() */
7124 : /************************************************************************/
7125 :
7126 : /**
7127 : * \brief Update this layer with features from the update layer.
7128 : *
7129 : * The result layer contains features whose geometries represent areas
7130 : * that are either in the input layer or in the method layer. The
7131 : * features in the result layer have areas of the features of the
7132 : * method layer or those ares of the features of the input layer that
7133 : * are not covered by the method layer. The features of the result
7134 : * layer get their attributes from the input layer. The schema of the
7135 : * result layer can be set by the user or, if it is empty, is
7136 : * initialized to contain all fields in the input layer.
7137 : *
7138 : * \note If the schema of the result is set by user and contains
7139 : * fields that have the same name as a field in the method layer, then
7140 : * the attribute in the result feature the originates from the method
7141 : * layer will get the value from the feature of the method layer.
7142 : *
7143 : * \note For best performance use the minimum amount of features in
7144 : * the method layer and copy it into a memory layer.
7145 : *
7146 : * \note This method relies on GEOS support. Do not use unless the
7147 : * GEOS support is compiled in.
7148 : *
7149 : * The recognized list of options is :
7150 : * <ul>
7151 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7152 : * feature could not be inserted or a GEOS call failed.
7153 : * </li>
7154 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7155 : * into MultiPolygons, LineStrings to MultiLineStrings or
7156 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
7157 : * </li>
7158 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7159 : * will be created from the fields of the input layer.
7160 : * </li>
7161 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7162 : * will be created from the fields of the method layer.
7163 : * </li>
7164 : * </ul>
7165 : *
7166 : * This method is the same as the C function OGR_L_Update().
7167 : *
7168 : * @param pLayerMethod the method layer. Should not be NULL.
7169 : *
7170 : * @param pLayerResult the layer where the features resulting from the
7171 : * operation are inserted. Should not be NULL. See above the note
7172 : * about the schema.
7173 : *
7174 : * @param papszOptions NULL terminated list of options (may be NULL).
7175 : *
7176 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
7177 : * reporting progress or NULL.
7178 : *
7179 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7180 : *
7181 : * @return an error code if there was an error or the execution was
7182 : * interrupted, OGRERR_NONE otherwise.
7183 : *
7184 : * @note The first geometry field is always used.
7185 : *
7186 : * @since OGR 1.10
7187 : */
7188 :
7189 6 : OGRErr OGRLayer::Update(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
7190 : CSLConstList papszOptions, GDALProgressFunc pfnProgress,
7191 : void *pProgressArg)
7192 : {
7193 6 : OGRErr ret = OGRERR_NONE;
7194 6 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
7195 6 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
7196 6 : OGRFeatureDefn *poDefnResult = nullptr;
7197 6 : OGRGeometry *pGeometryMethodFilter = nullptr;
7198 6 : int *mapInput = nullptr;
7199 6 : int *mapMethod = nullptr;
7200 : double progress_max =
7201 6 : static_cast<double>(GetFeatureCount(FALSE)) +
7202 6 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
7203 6 : double progress_counter = 0;
7204 6 : double progress_ticker = 0;
7205 : const bool bSkipFailures =
7206 6 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
7207 6 : const bool bPromoteToMulti = CPLTestBool(
7208 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
7209 :
7210 : // check for GEOS
7211 6 : if (!OGRGeometryFactory::haveGEOS())
7212 : {
7213 0 : CPLError(CE_Failure, CPLE_AppDefined,
7214 : "OGRLayer::Update() requires GEOS support");
7215 0 : return OGRERR_UNSUPPORTED_OPERATION;
7216 : }
7217 :
7218 : // get resources
7219 6 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
7220 6 : if (ret != OGRERR_NONE)
7221 0 : goto done;
7222 6 : ret = create_field_map(poDefnInput, &mapInput);
7223 6 : if (ret != OGRERR_NONE)
7224 0 : goto done;
7225 6 : ret = create_field_map(poDefnMethod, &mapMethod);
7226 6 : if (ret != OGRERR_NONE)
7227 0 : goto done;
7228 6 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
7229 : mapMethod, false, papszOptions);
7230 6 : if (ret != OGRERR_NONE)
7231 0 : goto done;
7232 6 : poDefnResult = pLayerResult->GetLayerDefn();
7233 :
7234 : // add clipped features from the input layer
7235 18 : for (auto &&x : this)
7236 : {
7237 :
7238 12 : if (pfnProgress)
7239 : {
7240 2 : double p = progress_counter / progress_max;
7241 2 : if (p > progress_ticker)
7242 : {
7243 1 : if (!pfnProgress(p, "", pProgressArg))
7244 : {
7245 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7246 0 : ret = OGRERR_FAILURE;
7247 0 : goto done;
7248 : }
7249 : }
7250 2 : progress_counter += 1.0;
7251 : }
7252 :
7253 : // set up the filter on method layer
7254 12 : CPLErrorReset();
7255 : OGRGeometry *x_geom =
7256 12 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
7257 12 : if (CPLGetLastErrorType() != CE_None)
7258 : {
7259 0 : if (!bSkipFailures)
7260 : {
7261 0 : ret = OGRERR_FAILURE;
7262 0 : goto done;
7263 : }
7264 : else
7265 : {
7266 0 : CPLErrorReset();
7267 0 : ret = OGRERR_NONE;
7268 : }
7269 : }
7270 12 : if (!x_geom)
7271 : {
7272 0 : continue;
7273 : }
7274 :
7275 : OGRGeometryUniquePtr x_geom_diff(
7276 12 : x_geom->clone()); // this will be the geometry of a result feature
7277 28 : for (auto &&y : pLayerMethod)
7278 : {
7279 16 : OGRGeometry *y_geom = y->GetGeometryRef();
7280 16 : if (!y_geom)
7281 0 : continue;
7282 16 : if (x_geom_diff)
7283 : {
7284 16 : CPLErrorReset();
7285 : OGRGeometryUniquePtr x_geom_diff_new(
7286 16 : x_geom_diff->Difference(y_geom));
7287 32 : if (CPLGetLastErrorType() != CE_None ||
7288 16 : x_geom_diff_new == nullptr)
7289 : {
7290 0 : if (!bSkipFailures)
7291 : {
7292 0 : ret = OGRERR_FAILURE;
7293 0 : goto done;
7294 : }
7295 : else
7296 : {
7297 0 : CPLErrorReset();
7298 0 : ret = OGRERR_NONE;
7299 : }
7300 : }
7301 : else
7302 : {
7303 16 : x_geom_diff.swap(x_geom_diff_new);
7304 : }
7305 : }
7306 : }
7307 :
7308 12 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
7309 : {
7310 : /* ok */
7311 : }
7312 : else
7313 : {
7314 7 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
7315 7 : z->SetFieldsFrom(x.get(), mapInput);
7316 7 : if (bPromoteToMulti)
7317 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
7318 7 : z->SetGeometryDirectly(x_geom_diff.release());
7319 7 : ret = pLayerResult->CreateFeature(z.get());
7320 7 : if (ret != OGRERR_NONE)
7321 : {
7322 0 : if (!bSkipFailures)
7323 : {
7324 0 : goto done;
7325 : }
7326 : else
7327 : {
7328 0 : CPLErrorReset();
7329 0 : ret = OGRERR_NONE;
7330 : }
7331 : }
7332 : }
7333 : }
7334 :
7335 : // restore the original filter and add features from the update layer
7336 6 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
7337 16 : for (auto &&y : pLayerMethod)
7338 : {
7339 :
7340 10 : if (pfnProgress)
7341 : {
7342 1 : double p = progress_counter / progress_max;
7343 1 : if (p > progress_ticker)
7344 : {
7345 1 : if (!pfnProgress(p, "", pProgressArg))
7346 : {
7347 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7348 0 : ret = OGRERR_FAILURE;
7349 0 : goto done;
7350 : }
7351 : }
7352 1 : progress_counter += 1.0;
7353 : }
7354 :
7355 10 : OGRGeometry *y_geom = y->StealGeometry();
7356 10 : if (!y_geom)
7357 0 : continue;
7358 10 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
7359 10 : if (mapMethod)
7360 6 : z->SetFieldsFrom(y.get(), mapMethod);
7361 10 : z->SetGeometryDirectly(y_geom);
7362 10 : ret = pLayerResult->CreateFeature(z.get());
7363 10 : if (ret != OGRERR_NONE)
7364 : {
7365 0 : if (!bSkipFailures)
7366 : {
7367 0 : goto done;
7368 : }
7369 : else
7370 : {
7371 0 : CPLErrorReset();
7372 0 : ret = OGRERR_NONE;
7373 : }
7374 : }
7375 : }
7376 6 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
7377 : {
7378 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7379 0 : ret = OGRERR_FAILURE;
7380 0 : goto done;
7381 : }
7382 6 : done:
7383 : // release resources
7384 6 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
7385 6 : if (pGeometryMethodFilter)
7386 0 : delete pGeometryMethodFilter;
7387 6 : if (mapInput)
7388 4 : VSIFree(mapInput);
7389 6 : if (mapMethod)
7390 4 : VSIFree(mapMethod);
7391 6 : return ret;
7392 : }
7393 :
7394 : /************************************************************************/
7395 : /* OGR_L_Update() */
7396 : /************************************************************************/
7397 :
7398 : /**
7399 : * \brief Update this layer with features from the update layer.
7400 : *
7401 : * The result layer contains features whose geometries represent areas
7402 : * that are either in the input layer or in the method layer. The
7403 : * features in the result layer have areas of the features of the
7404 : * method layer or those ares of the features of the input layer that
7405 : * are not covered by the method layer. The features of the result
7406 : * layer get their attributes from the input layer. The schema of the
7407 : * result layer can be set by the user or, if it is empty, is
7408 : * initialized to contain all fields in the input layer.
7409 : *
7410 : * \note If the schema of the result is set by user and contains
7411 : * fields that have the same name as a field in the method layer, then
7412 : * the attribute in the result feature the originates from the method
7413 : * layer will get the value from the feature of the method layer.
7414 : *
7415 : * \note For best performance use the minimum amount of features in
7416 : * the method layer and copy it into a memory layer.
7417 : *
7418 : * \note This method relies on GEOS support. Do not use unless the
7419 : * GEOS support is compiled in.
7420 : *
7421 : * The recognized list of options is :
7422 : * <ul>
7423 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7424 : * feature could not be inserted or a GEOS call failed.
7425 : * </li>
7426 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7427 : * into MultiPolygons, LineStrings to MultiLineStrings or
7428 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
7429 : * </li>
7430 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7431 : * will be created from the fields of the input layer.
7432 : * </li>
7433 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7434 : * will be created from the fields of the method layer.
7435 : * </li>
7436 : * </ul>
7437 : *
7438 : * This function is the same as the C++ method OGRLayer::Update().
7439 : *
7440 : * @param pLayerInput the input layer. Should not be NULL.
7441 : *
7442 : * @param pLayerMethod the method layer. Should not be NULL.
7443 : *
7444 : * @param pLayerResult the layer where the features resulting from the
7445 : * operation are inserted. Should not be NULL. See above the note
7446 : * about the schema.
7447 : *
7448 : * @param papszOptions NULL terminated list of options (may be NULL).
7449 : *
7450 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
7451 : * reporting progress or NULL.
7452 : *
7453 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7454 : *
7455 : * @return an error code if there was an error or the execution was
7456 : * interrupted, OGRERR_NONE otherwise.
7457 : *
7458 : * @note The first geometry field is always used.
7459 : *
7460 : * @since OGR 1.10
7461 : */
7462 :
7463 5 : OGRErr OGR_L_Update(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
7464 : OGRLayerH pLayerResult, CSLConstList papszOptions,
7465 : GDALProgressFunc pfnProgress, void *pProgressArg)
7466 :
7467 : {
7468 5 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE);
7469 5 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE);
7470 5 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE);
7471 :
7472 : return OGRLayer::FromHandle(pLayerInput)
7473 5 : ->Update(OGRLayer::FromHandle(pLayerMethod),
7474 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
7475 5 : pProgressArg);
7476 : }
7477 :
7478 : /************************************************************************/
7479 : /* Clip() */
7480 : /************************************************************************/
7481 :
7482 : /**
7483 : * \brief Clip off areas that are not covered by the method layer.
7484 : *
7485 : * The result layer contains features whose geometries represent areas
7486 : * that are in the input layer and in the method layer. The features
7487 : * in the result layer have the (possibly clipped) areas of features
7488 : * in the input layer and the attributes from the same features. The
7489 : * schema of the result layer can be set by the user or, if it is
7490 : * empty, is initialized to contain all fields in the input layer.
7491 : *
7492 : * \note For best performance use the minimum amount of features in
7493 : * the method layer and copy it into a memory layer.
7494 : *
7495 : * \note This method relies on GEOS support. Do not use unless the
7496 : * GEOS support is compiled in.
7497 : *
7498 : * The recognized list of options is :
7499 : * <ul>
7500 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7501 : * feature could not be inserted or a GEOS call failed.
7502 : * </li>
7503 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7504 : * into MultiPolygons, LineStrings to MultiLineStrings or
7505 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
7506 : * </li>
7507 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7508 : * will be created from the fields of the input layer.
7509 : * </li>
7510 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7511 : * will be created from the fields of the method layer.
7512 : * </li>
7513 : * </ul>
7514 : *
7515 : * This method is the same as the C function OGR_L_Clip().
7516 : *
7517 : * @param pLayerMethod the method layer. Should not be NULL.
7518 : *
7519 : * @param pLayerResult the layer where the features resulting from the
7520 : * operation are inserted. Should not be NULL. See above the note
7521 : * about the schema.
7522 : *
7523 : * @param papszOptions NULL terminated list of options (may be NULL).
7524 : *
7525 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
7526 : * reporting progress or NULL.
7527 : *
7528 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7529 : *
7530 : * @return an error code if there was an error or the execution was
7531 : * interrupted, OGRERR_NONE otherwise.
7532 : *
7533 : * @note The first geometry field is always used.
7534 : *
7535 : * @since OGR 1.10
7536 : */
7537 :
7538 4 : OGRErr OGRLayer::Clip(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
7539 : CSLConstList papszOptions, GDALProgressFunc pfnProgress,
7540 : void *pProgressArg)
7541 : {
7542 4 : OGRErr ret = OGRERR_NONE;
7543 4 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
7544 4 : OGRFeatureDefn *poDefnResult = nullptr;
7545 4 : OGRGeometry *pGeometryMethodFilter = nullptr;
7546 4 : int *mapInput = nullptr;
7547 4 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
7548 4 : double progress_counter = 0;
7549 4 : double progress_ticker = 0;
7550 : const bool bSkipFailures =
7551 4 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
7552 4 : const bool bPromoteToMulti = CPLTestBool(
7553 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
7554 :
7555 : // check for GEOS
7556 4 : if (!OGRGeometryFactory::haveGEOS())
7557 : {
7558 0 : CPLError(CE_Failure, CPLE_AppDefined,
7559 : "OGRLayer::Clip() requires GEOS support");
7560 0 : return OGRERR_UNSUPPORTED_OPERATION;
7561 : }
7562 :
7563 4 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
7564 4 : if (ret != OGRERR_NONE)
7565 0 : goto done;
7566 4 : ret = create_field_map(poDefnInput, &mapInput);
7567 4 : if (ret != OGRERR_NONE)
7568 0 : goto done;
7569 4 : ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
7570 : nullptr, false, papszOptions);
7571 4 : if (ret != OGRERR_NONE)
7572 0 : goto done;
7573 :
7574 4 : poDefnResult = pLayerResult->GetLayerDefn();
7575 12 : for (auto &&x : this)
7576 : {
7577 :
7578 8 : if (pfnProgress)
7579 : {
7580 2 : double p = progress_counter / progress_max;
7581 2 : if (p > progress_ticker)
7582 : {
7583 1 : if (!pfnProgress(p, "", pProgressArg))
7584 : {
7585 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7586 0 : ret = OGRERR_FAILURE;
7587 0 : goto done;
7588 : }
7589 : }
7590 2 : progress_counter += 1.0;
7591 : }
7592 :
7593 : // set up the filter on method layer
7594 8 : CPLErrorReset();
7595 : OGRGeometry *x_geom =
7596 8 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
7597 8 : if (CPLGetLastErrorType() != CE_None)
7598 : {
7599 0 : if (!bSkipFailures)
7600 : {
7601 0 : ret = OGRERR_FAILURE;
7602 0 : goto done;
7603 : }
7604 : else
7605 : {
7606 0 : CPLErrorReset();
7607 0 : ret = OGRERR_NONE;
7608 : }
7609 : }
7610 8 : if (!x_geom)
7611 : {
7612 0 : continue;
7613 : }
7614 :
7615 : OGRGeometryUniquePtr
7616 0 : geom; // this will be the geometry of the result feature
7617 : // incrementally add area from y to geom
7618 16 : for (auto &&y : pLayerMethod)
7619 : {
7620 8 : OGRGeometry *y_geom = y->GetGeometryRef();
7621 8 : if (!y_geom)
7622 0 : continue;
7623 8 : if (!geom)
7624 : {
7625 8 : geom.reset(y_geom->clone());
7626 : }
7627 : else
7628 : {
7629 0 : CPLErrorReset();
7630 0 : OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
7631 0 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
7632 : {
7633 0 : if (!bSkipFailures)
7634 : {
7635 0 : ret = OGRERR_FAILURE;
7636 0 : goto done;
7637 : }
7638 : else
7639 : {
7640 0 : CPLErrorReset();
7641 0 : ret = OGRERR_NONE;
7642 : }
7643 : }
7644 : else
7645 : {
7646 0 : geom.swap(geom_new);
7647 : }
7648 : }
7649 : }
7650 :
7651 : // possibly add a new feature with area x intersection sum of y
7652 8 : if (geom)
7653 : {
7654 8 : CPLErrorReset();
7655 : OGRGeometryUniquePtr poIntersection(
7656 8 : x_geom->Intersection(geom.get()));
7657 8 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
7658 : {
7659 0 : if (!bSkipFailures)
7660 : {
7661 0 : ret = OGRERR_FAILURE;
7662 0 : goto done;
7663 : }
7664 : else
7665 : {
7666 0 : CPLErrorReset();
7667 0 : ret = OGRERR_NONE;
7668 : }
7669 : }
7670 8 : else if (!poIntersection->IsEmpty())
7671 : {
7672 8 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
7673 8 : z->SetFieldsFrom(x.get(), mapInput);
7674 8 : if (bPromoteToMulti)
7675 2 : poIntersection.reset(
7676 : promote_to_multi(poIntersection.release()));
7677 8 : z->SetGeometryDirectly(poIntersection.release());
7678 8 : ret = pLayerResult->CreateFeature(z.get());
7679 8 : if (ret != OGRERR_NONE)
7680 : {
7681 0 : if (!bSkipFailures)
7682 : {
7683 0 : goto done;
7684 : }
7685 : else
7686 : {
7687 0 : CPLErrorReset();
7688 0 : ret = OGRERR_NONE;
7689 : }
7690 : }
7691 : }
7692 : }
7693 : }
7694 4 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
7695 : {
7696 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7697 0 : ret = OGRERR_FAILURE;
7698 0 : goto done;
7699 : }
7700 4 : done:
7701 : // release resources
7702 4 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
7703 4 : if (pGeometryMethodFilter)
7704 0 : delete pGeometryMethodFilter;
7705 4 : if (mapInput)
7706 4 : VSIFree(mapInput);
7707 4 : return ret;
7708 : }
7709 :
7710 : /************************************************************************/
7711 : /* OGR_L_Clip() */
7712 : /************************************************************************/
7713 :
7714 : /**
7715 : * \brief Clip off areas that are not covered by the method layer.
7716 : *
7717 : * The result layer contains features whose geometries represent areas
7718 : * that are in the input layer and in the method layer. The features
7719 : * in the result layer have the (possibly clipped) areas of features
7720 : * in the input layer and the attributes from the same features. The
7721 : * schema of the result layer can be set by the user or, if it is
7722 : * empty, is initialized to contain all fields in the input layer.
7723 : *
7724 : * \note For best performance use the minimum amount of features in
7725 : * the method layer and copy it into a memory layer.
7726 : *
7727 : * \note This method relies on GEOS support. Do not use unless the
7728 : * GEOS support is compiled in.
7729 : *
7730 : * The recognized list of options is :
7731 : * <ul>
7732 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7733 : * feature could not be inserted or a GEOS call failed.
7734 : * </li>
7735 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7736 : * into MultiPolygons, LineStrings to MultiLineStrings or
7737 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
7738 : * </li>
7739 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7740 : * will be created from the fields of the input layer.
7741 : * </li>
7742 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7743 : * will be created from the fields of the method layer.
7744 : * </li>
7745 : * </ul>
7746 : *
7747 : * This function is the same as the C++ method OGRLayer::Clip().
7748 : *
7749 : * @param pLayerInput the input layer. Should not be NULL.
7750 : *
7751 : * @param pLayerMethod the method layer. Should not be NULL.
7752 : *
7753 : * @param pLayerResult the layer where the features resulting from the
7754 : * operation are inserted. Should not be NULL. See above the note
7755 : * about the schema.
7756 : *
7757 : * @param papszOptions NULL terminated list of options (may be NULL).
7758 : *
7759 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
7760 : * reporting progress or NULL.
7761 : *
7762 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7763 : *
7764 : * @return an error code if there was an error or the execution was
7765 : * interrupted, OGRERR_NONE otherwise.
7766 : *
7767 : * @note The first geometry field is always used.
7768 : *
7769 : * @since OGR 1.10
7770 : */
7771 :
7772 3 : OGRErr OGR_L_Clip(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
7773 : OGRLayerH pLayerResult, CSLConstList papszOptions,
7774 : GDALProgressFunc pfnProgress, void *pProgressArg)
7775 :
7776 : {
7777 3 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
7778 3 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
7779 3 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
7780 :
7781 : return OGRLayer::FromHandle(pLayerInput)
7782 3 : ->Clip(OGRLayer::FromHandle(pLayerMethod),
7783 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
7784 3 : pProgressArg);
7785 : }
7786 :
7787 : /************************************************************************/
7788 : /* Erase() */
7789 : /************************************************************************/
7790 :
7791 : /**
7792 : * \brief Remove areas that are covered by the method layer.
7793 : *
7794 : * The result layer contains features whose geometries represent areas
7795 : * that are in the input layer but not in the method layer. The
7796 : * features in the result layer have attributes from the input
7797 : * layer. The schema of the result layer can be set by the user or, if
7798 : * it is empty, is initialized to contain all fields in the input
7799 : * layer.
7800 : *
7801 : * \note For best performance use the minimum amount of features in
7802 : * the method layer and copy it into a memory layer.
7803 : *
7804 : * \note This method relies on GEOS support. Do not use unless the
7805 : * GEOS support is compiled in.
7806 : *
7807 : * The recognized list of options is :
7808 : * <ul>
7809 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
7810 : * feature could not be inserted or a GEOS call failed.
7811 : * </li>
7812 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
7813 : * into MultiPolygons, LineStrings to MultiLineStrings or
7814 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
7815 : * </li>
7816 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
7817 : * will be created from the fields of the input layer.
7818 : * </li>
7819 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
7820 : * will be created from the fields of the method layer.
7821 : * </li>
7822 : * </ul>
7823 : *
7824 : * This method is the same as the C function OGR_L_Erase().
7825 : *
7826 : * @param pLayerMethod the method layer. Should not be NULL.
7827 : *
7828 : * @param pLayerResult the layer where the features resulting from the
7829 : * operation are inserted. Should not be NULL. See above the note
7830 : * about the schema.
7831 : *
7832 : * @param papszOptions NULL terminated list of options (may be NULL).
7833 : *
7834 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
7835 : * reporting progress or NULL.
7836 : *
7837 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
7838 : *
7839 : * @return an error code if there was an error or the execution was
7840 : * interrupted, OGRERR_NONE otherwise.
7841 : *
7842 : * @note The first geometry field is always used.
7843 : *
7844 : * @since OGR 1.10
7845 : */
7846 :
7847 7 : OGRErr OGRLayer::Erase(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
7848 : CSLConstList papszOptions, GDALProgressFunc pfnProgress,
7849 : void *pProgressArg)
7850 : {
7851 7 : OGRErr ret = OGRERR_NONE;
7852 7 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
7853 7 : OGRFeatureDefn *poDefnResult = nullptr;
7854 7 : OGRGeometry *pGeometryMethodFilter = nullptr;
7855 7 : int *mapInput = nullptr;
7856 7 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
7857 7 : double progress_counter = 0;
7858 7 : double progress_ticker = 0;
7859 : const bool bSkipFailures =
7860 7 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
7861 7 : const bool bPromoteToMulti = CPLTestBool(
7862 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
7863 :
7864 : // check for GEOS
7865 7 : if (!OGRGeometryFactory::haveGEOS())
7866 : {
7867 0 : CPLError(CE_Failure, CPLE_AppDefined,
7868 : "OGRLayer::Erase() requires GEOS support");
7869 0 : return OGRERR_UNSUPPORTED_OPERATION;
7870 : }
7871 :
7872 : // get resources
7873 7 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
7874 7 : if (ret != OGRERR_NONE)
7875 0 : goto done;
7876 7 : ret = create_field_map(poDefnInput, &mapInput);
7877 7 : if (ret != OGRERR_NONE)
7878 0 : goto done;
7879 7 : ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
7880 : nullptr, false, papszOptions);
7881 7 : if (ret != OGRERR_NONE)
7882 0 : goto done;
7883 7 : poDefnResult = pLayerResult->GetLayerDefn();
7884 :
7885 21 : for (auto &&x : this)
7886 : {
7887 :
7888 14 : if (pfnProgress)
7889 : {
7890 2 : double p = progress_counter / progress_max;
7891 2 : if (p > progress_ticker)
7892 : {
7893 1 : if (!pfnProgress(p, "", pProgressArg))
7894 : {
7895 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7896 0 : ret = OGRERR_FAILURE;
7897 0 : goto done;
7898 : }
7899 : }
7900 2 : progress_counter += 1.0;
7901 : }
7902 :
7903 : // set up the filter on the method layer
7904 14 : CPLErrorReset();
7905 : OGRGeometry *x_geom =
7906 14 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
7907 14 : if (CPLGetLastErrorType() != CE_None)
7908 : {
7909 0 : if (!bSkipFailures)
7910 : {
7911 0 : ret = OGRERR_FAILURE;
7912 0 : goto done;
7913 : }
7914 : else
7915 : {
7916 0 : CPLErrorReset();
7917 0 : ret = OGRERR_NONE;
7918 : }
7919 : }
7920 14 : if (!x_geom)
7921 : {
7922 0 : continue;
7923 : }
7924 :
7925 : OGRGeometryUniquePtr geom(
7926 : x_geom
7927 14 : ->clone()); // this will be the geometry of the result feature
7928 : // incrementally erase y from geom
7929 22 : for (auto &&y : pLayerMethod)
7930 : {
7931 11 : OGRGeometry *y_geom = y->GetGeometryRef();
7932 11 : if (!y_geom)
7933 0 : continue;
7934 11 : CPLErrorReset();
7935 11 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
7936 11 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
7937 : {
7938 0 : if (!bSkipFailures)
7939 : {
7940 0 : ret = OGRERR_FAILURE;
7941 0 : goto done;
7942 : }
7943 : else
7944 : {
7945 0 : CPLErrorReset();
7946 0 : ret = OGRERR_NONE;
7947 : }
7948 : }
7949 : else
7950 : {
7951 11 : geom.swap(geom_new);
7952 11 : if (geom->IsEmpty())
7953 : {
7954 3 : break;
7955 : }
7956 : }
7957 : }
7958 :
7959 : // add a new feature if there is remaining area
7960 14 : if (!geom->IsEmpty())
7961 : {
7962 11 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
7963 11 : z->SetFieldsFrom(x.get(), mapInput);
7964 11 : if (bPromoteToMulti)
7965 4 : geom.reset(promote_to_multi(geom.release()));
7966 11 : z->SetGeometryDirectly(geom.release());
7967 11 : ret = pLayerResult->CreateFeature(z.get());
7968 11 : if (ret != OGRERR_NONE)
7969 : {
7970 0 : if (!bSkipFailures)
7971 : {
7972 0 : goto done;
7973 : }
7974 : else
7975 : {
7976 0 : CPLErrorReset();
7977 0 : ret = OGRERR_NONE;
7978 : }
7979 : }
7980 : }
7981 : }
7982 7 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
7983 : {
7984 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
7985 0 : ret = OGRERR_FAILURE;
7986 0 : goto done;
7987 : }
7988 7 : done:
7989 : // release resources
7990 7 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
7991 7 : if (pGeometryMethodFilter)
7992 0 : delete pGeometryMethodFilter;
7993 7 : if (mapInput)
7994 6 : VSIFree(mapInput);
7995 7 : return ret;
7996 : }
7997 :
7998 : /************************************************************************/
7999 : /* OGR_L_Erase() */
8000 : /************************************************************************/
8001 :
8002 : /**
8003 : * \brief Remove areas that are covered by the method layer.
8004 : *
8005 : * The result layer contains features whose geometries represent areas
8006 : * that are in the input layer but not in the method layer. The
8007 : * features in the result layer have attributes from the input
8008 : * layer. The schema of the result layer can be set by the user or, if
8009 : * it is empty, is initialized to contain all fields in the input
8010 : * layer.
8011 : *
8012 : * \note For best performance use the minimum amount of features in
8013 : * the method layer and copy it into a memory layer.
8014 : *
8015 : * \note This method relies on GEOS support. Do not use unless the
8016 : * GEOS support is compiled in.
8017 : *
8018 : * The recognized list of options is :
8019 : * <ul>
8020 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
8021 : * feature could not be inserted or a GEOS call failed.
8022 : * </li>
8023 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
8024 : * into MultiPolygons, LineStrings to MultiLineStrings or
8025 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
8026 : * </li>
8027 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
8028 : * will be created from the fields of the input layer.
8029 : * </li>
8030 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
8031 : * will be created from the fields of the method layer.
8032 : * </li>
8033 : * </ul>
8034 : *
8035 : * This function is the same as the C++ method OGRLayer::Erase().
8036 : *
8037 : * @param pLayerInput the input layer. Should not be NULL.
8038 : *
8039 : * @param pLayerMethod the method layer. Should not be NULL.
8040 : *
8041 : * @param pLayerResult the layer where the features resulting from the
8042 : * operation are inserted. Should not be NULL. See above the note
8043 : * about the schema.
8044 : *
8045 : * @param papszOptions NULL terminated list of options (may be NULL).
8046 : *
8047 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
8048 : * reporting progress or NULL.
8049 : *
8050 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
8051 : *
8052 : * @return an error code if there was an error or the execution was
8053 : * interrupted, OGRERR_NONE otherwise.
8054 : *
8055 : * @note The first geometry field is always used.
8056 : *
8057 : * @since OGR 1.10
8058 : */
8059 :
8060 6 : OGRErr OGR_L_Erase(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
8061 : OGRLayerH pLayerResult, CSLConstList papszOptions,
8062 : GDALProgressFunc pfnProgress, void *pProgressArg)
8063 :
8064 : {
8065 6 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
8066 6 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
8067 6 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
8068 :
8069 : return OGRLayer::FromHandle(pLayerInput)
8070 6 : ->Erase(OGRLayer::FromHandle(pLayerMethod),
8071 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
8072 6 : pProgressArg);
8073 : }
8074 :
8075 : /************************************************************************/
8076 : /* OGRLayer::FeatureIterator::Private */
8077 : /************************************************************************/
8078 :
8079 : struct OGRLayer::FeatureIterator::Private
8080 : {
8081 : CPL_DISALLOW_COPY_ASSIGN(Private)
8082 40154 : Private() = default;
8083 :
8084 : OGRFeatureUniquePtr m_poFeature{};
8085 : OGRLayer *m_poLayer = nullptr;
8086 : bool m_bError = false;
8087 : bool m_bEOF = true;
8088 : };
8089 :
8090 : /************************************************************************/
8091 : /* OGRLayer::FeatureIterator::FeatureIterator() */
8092 : /************************************************************************/
8093 :
8094 40154 : OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
8095 40154 : : m_poPrivate(new OGRLayer::FeatureIterator::Private())
8096 : {
8097 40154 : m_poPrivate->m_poLayer = poLayer;
8098 40154 : if (bStart)
8099 : {
8100 20077 : if (m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator)
8101 : {
8102 1 : CPLError(CE_Failure, CPLE_NotSupported,
8103 : "Only one feature iterator can be "
8104 : "active at a time");
8105 1 : m_poPrivate->m_bError = true;
8106 : }
8107 : else
8108 : {
8109 20076 : m_poPrivate->m_poLayer->ResetReading();
8110 40152 : m_poPrivate->m_poFeature.reset(
8111 20076 : m_poPrivate->m_poLayer->GetNextFeature());
8112 20076 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
8113 20076 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
8114 : }
8115 : }
8116 40154 : }
8117 :
8118 : /************************************************************************/
8119 : /* ~OGRLayer::FeatureIterator::FeatureIterator() */
8120 : /************************************************************************/
8121 :
8122 40154 : OGRLayer::FeatureIterator::~FeatureIterator()
8123 : {
8124 40154 : if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
8125 40153 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
8126 40154 : }
8127 :
8128 : /************************************************************************/
8129 : /* operator*() */
8130 : /************************************************************************/
8131 :
8132 169687 : OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
8133 : {
8134 169687 : return m_poPrivate->m_poFeature;
8135 : }
8136 :
8137 : /************************************************************************/
8138 : /* operator++() */
8139 : /************************************************************************/
8140 :
8141 168930 : OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
8142 : {
8143 168930 : m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
8144 168930 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
8145 168930 : return *this;
8146 : }
8147 :
8148 : /************************************************************************/
8149 : /* operator!=() */
8150 : /************************************************************************/
8151 :
8152 189007 : bool OGRLayer::FeatureIterator::operator!=(
8153 : const OGRLayer::FeatureIterator &it) const
8154 : {
8155 189007 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
8156 : }
8157 :
8158 : /************************************************************************/
8159 : /* begin() */
8160 : /************************************************************************/
8161 :
8162 20077 : OGRLayer::FeatureIterator OGRLayer::begin()
8163 : {
8164 20077 : return {this, true};
8165 : }
8166 :
8167 : /************************************************************************/
8168 : /* end() */
8169 : /************************************************************************/
8170 :
8171 20077 : OGRLayer::FeatureIterator OGRLayer::end()
8172 : {
8173 20077 : return {this, false};
8174 : }
8175 :
8176 : /************************************************************************/
8177 : /* OGRLayer::GetGeometryTypes() */
8178 : /************************************************************************/
8179 :
8180 : /** \brief Get actual geometry types found in features.
8181 : *
8182 : * This method iterates over features to retrieve their geometry types. This
8183 : * is mostly useful for layers that report a wkbUnknown geometry type with
8184 : * GetGeomType() or GetGeomFieldDefn(iGeomField)->GetType().
8185 : *
8186 : * By default this method returns an array of nEntryCount entries with each
8187 : * geometry type (in OGRGeometryTypeCounter::eGeomType) and the corresponding
8188 : * number of features (in OGRGeometryTypeCounter::nCount).
8189 : * Features without geometries are reported as eGeomType == wkbNone.
8190 : *
8191 : * The nFlagsGGT parameter can be a combination (with binary or operator) of the
8192 : * following hints:
8193 : * <ul>
8194 : * <li>OGR_GGT_COUNT_NOT_NEEDED: to indicate that only the set of geometry types
8195 : * matter, not the number of features per geometry type. Consequently the value
8196 : * of OGRGeometryTypeCounter::nCount should be ignored.</li>
8197 : * <li>OGR_GGT_STOP_IF_MIXED: to indicate that the implementation may stop
8198 : * iterating over features as soon as 2 different geometry types (not counting
8199 : * null geometries) are found. The value of OGRGeometryTypeCounter::nCount
8200 : * should be ignored (zero might be systematically reported by some
8201 : * implementations).</li> <li>OGR_GGT_GEOMCOLLECTIONZ_TINZ: to indicate that if
8202 : * a geometry is of type wkbGeometryCollection25D and its first sub-geometry is
8203 : * of type wkbTINZ, wkbTINZ should be reported as geometry type. This is mostly
8204 : * useful for the ESRI Shapefile and (Open)FileGDB drivers regarding MultiPatch
8205 : * geometries.</li>
8206 : * </ul>
8207 : *
8208 : * If the layer has no features, a non-NULL returned array with nEntryCount == 0
8209 : * will be returned.
8210 : *
8211 : * Spatial and/or attribute filters will be taken into account.
8212 : *
8213 : * This method will error out on a layer without geometry fields
8214 : * (GetGeomType() == wkbNone).
8215 : *
8216 : * A cancellation callback may be provided. The progress percentage it is called
8217 : * with is not relevant. The callback should return TRUE if processing should go
8218 : * on, or FALSE if it should be interrupted.
8219 : *
8220 : * @param iGeomField Geometry field index.
8221 : * @param nFlagsGGT Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
8222 : * OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
8223 : * @param[out] nEntryCountOut Number of entries in the returned array.
8224 : * @param pfnProgress Cancellation callback. May be NULL.
8225 : * @param pProgressData User data for the cancellation callback. May be NULL.
8226 : * @return an array of nEntryCount that must be freed with CPLFree(),
8227 : * or NULL in case of error
8228 : * @since GDAL 3.6
8229 : */
8230 : OGRGeometryTypeCounter *
8231 12 : OGRLayer::GetGeometryTypes(int iGeomField, int nFlagsGGT, int &nEntryCountOut,
8232 : GDALProgressFunc pfnProgress, void *pProgressData)
8233 : {
8234 12 : OGRFeatureDefn *poDefn = GetLayerDefn();
8235 12 : const int nGeomFieldCount = poDefn->GetGeomFieldCount();
8236 12 : if (iGeomField < 0 || iGeomField >= nGeomFieldCount)
8237 : {
8238 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for iGeomField");
8239 1 : nEntryCountOut = 0;
8240 1 : return nullptr;
8241 : }
8242 :
8243 : // Ignore all fields but the geometry one of interest
8244 22 : CPLStringList aosIgnoredFieldsRestore;
8245 22 : CPLStringList aosIgnoredFields;
8246 11 : const int nFieldCount = poDefn->GetFieldCount();
8247 33 : for (int iField = 0; iField < nFieldCount; iField++)
8248 : {
8249 22 : const auto poFieldDefn = poDefn->GetFieldDefn(iField);
8250 22 : const char *pszName = poFieldDefn->GetNameRef();
8251 22 : if (poFieldDefn->IsIgnored())
8252 10 : aosIgnoredFieldsRestore.AddString(pszName);
8253 22 : if (iField != iGeomField)
8254 11 : aosIgnoredFields.AddString(pszName);
8255 : }
8256 33 : for (int iField = 0; iField < nGeomFieldCount; iField++)
8257 : {
8258 22 : const auto poFieldDefn = poDefn->GetGeomFieldDefn(iField);
8259 22 : const char *pszName = poFieldDefn->GetNameRef();
8260 22 : if (poFieldDefn->IsIgnored())
8261 10 : aosIgnoredFieldsRestore.AddString(pszName);
8262 22 : if (iField != iGeomField)
8263 11 : aosIgnoredFields.AddString(pszName);
8264 : }
8265 11 : if (poDefn->IsStyleIgnored())
8266 0 : aosIgnoredFieldsRestore.AddString("OGR_STYLE");
8267 11 : aosIgnoredFields.AddString("OGR_STYLE");
8268 11 : SetIgnoredFields(aosIgnoredFields.List());
8269 :
8270 : // Iterate over features
8271 22 : std::map<OGRwkbGeometryType, int64_t> oMapCount;
8272 22 : std::set<OGRwkbGeometryType> oSetNotNull;
8273 11 : const bool bGeomCollectionZTInZ =
8274 11 : (nFlagsGGT & OGR_GGT_GEOMCOLLECTIONZ_TINZ) != 0;
8275 11 : const bool bStopIfMixed = (nFlagsGGT & OGR_GGT_STOP_IF_MIXED) != 0;
8276 11 : if (pfnProgress == GDALDummyProgress)
8277 0 : pfnProgress = nullptr;
8278 11 : bool bInterrupted = false;
8279 47 : for (auto &&poFeature : *this)
8280 : {
8281 36 : const auto poGeom = poFeature->GetGeomFieldRef(iGeomField);
8282 36 : if (poGeom == nullptr)
8283 : {
8284 18 : ++oMapCount[wkbNone];
8285 : }
8286 : else
8287 : {
8288 18 : auto eGeomType = poGeom->getGeometryType();
8289 18 : if (bGeomCollectionZTInZ && eGeomType == wkbGeometryCollection25D)
8290 : {
8291 1 : const auto poGC = poGeom->toGeometryCollection();
8292 1 : if (poGC->getNumGeometries() > 0)
8293 : {
8294 : auto eSubGeomType =
8295 1 : poGC->getGeometryRef(0)->getGeometryType();
8296 1 : if (eSubGeomType == wkbTINZ)
8297 1 : eGeomType = wkbTINZ;
8298 : }
8299 : }
8300 18 : ++oMapCount[eGeomType];
8301 18 : if (bStopIfMixed)
8302 : {
8303 4 : oSetNotNull.insert(eGeomType);
8304 4 : if (oSetNotNull.size() == 2)
8305 2 : break;
8306 : }
8307 : }
8308 34 : if (pfnProgress && !pfnProgress(0.0, "", pProgressData))
8309 : {
8310 1 : bInterrupted = true;
8311 1 : break;
8312 : }
8313 : }
8314 :
8315 : // Restore ignore fields state
8316 11 : SetIgnoredFields(aosIgnoredFieldsRestore.List());
8317 :
8318 11 : if (bInterrupted)
8319 : {
8320 1 : nEntryCountOut = 0;
8321 1 : return nullptr;
8322 : }
8323 :
8324 : // Format result
8325 10 : nEntryCountOut = static_cast<int>(oMapCount.size());
8326 : OGRGeometryTypeCounter *pasRet = static_cast<OGRGeometryTypeCounter *>(
8327 10 : CPLCalloc(1 + nEntryCountOut, sizeof(OGRGeometryTypeCounter)));
8328 10 : int i = 0;
8329 37 : for (const auto &oIter : oMapCount)
8330 : {
8331 27 : pasRet[i].eGeomType = oIter.first;
8332 27 : pasRet[i].nCount = oIter.second;
8333 27 : ++i;
8334 : }
8335 10 : return pasRet;
8336 : }
8337 :
8338 : /************************************************************************/
8339 : /* OGR_L_GetGeometryTypes() */
8340 : /************************************************************************/
8341 :
8342 : /** \brief Get actual geometry types found in features.
8343 : *
8344 : * See OGRLayer::GetGeometryTypes() for details.
8345 : *
8346 : * @param hLayer Layer.
8347 : * @param iGeomField Geometry field index.
8348 : * @param nFlags Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
8349 : * OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
8350 : * @param[out] pnEntryCount Pointer to the number of entries in the returned
8351 : * array. Must not be NULL.
8352 : * @param pfnProgress Cancellation callback. May be NULL.
8353 : * @param pProgressData User data for the cancellation callback. May be NULL.
8354 : * @return an array of *pnEntryCount that must be freed with CPLFree(),
8355 : * or NULL in case of error
8356 : * @since GDAL 3.6
8357 : */
8358 54 : OGRGeometryTypeCounter *OGR_L_GetGeometryTypes(OGRLayerH hLayer, int iGeomField,
8359 : int nFlags, int *pnEntryCount,
8360 : GDALProgressFunc pfnProgress,
8361 : void *pProgressData)
8362 : {
8363 54 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryTypes", nullptr);
8364 54 : VALIDATE_POINTER1(pnEntryCount, "OGR_L_GetGeometryTypes", nullptr);
8365 :
8366 108 : return OGRLayer::FromHandle(hLayer)->GetGeometryTypes(
8367 54 : iGeomField, nFlags, *pnEntryCount, pfnProgress, pProgressData);
8368 : }
8369 :
8370 : /************************************************************************/
8371 : /* OGRLayer::GetSupportedSRSList() */
8372 : /************************************************************************/
8373 :
8374 : /** \brief Get the list of SRS supported.
8375 : *
8376 : * The base implementation of this method will return an empty list. Some
8377 : * drivers (OAPIF, WFS) may return a non-empty list.
8378 : *
8379 : * One of the SRS returned may be passed to SetActiveSRS() to change the
8380 : * active SRS.
8381 : *
8382 : * @param iGeomField Geometry field index.
8383 : * @return list of supported SRS.
8384 : * @since GDAL 3.7
8385 : */
8386 : const OGRLayer::GetSupportedSRSListRetType &
8387 208 : OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
8388 : {
8389 208 : static OGRLayer::GetSupportedSRSListRetType empty;
8390 208 : return empty;
8391 : }
8392 :
8393 : /************************************************************************/
8394 : /* OGR_L_GetSupportedSRSList() */
8395 : /************************************************************************/
8396 :
8397 : /** \brief Get the list of SRS supported.
8398 : *
8399 : * The base implementation of this method will return an empty list. Some
8400 : * drivers (OAPIF, WFS) may return a non-empty list.
8401 : *
8402 : * One of the SRS returned may be passed to SetActiveSRS() to change the
8403 : * active SRS.
8404 : *
8405 : * @param hLayer Layer.
8406 : * @param iGeomField Geometry field index.
8407 : * @param[out] pnCount Number of values in returned array. Must not be null.
8408 : * @return list of supported SRS, to be freed with OSRFreeSRSArray(), or
8409 : * nullptr
8410 : * @since GDAL 3.7
8411 : */
8412 4 : OGRSpatialReferenceH *OGR_L_GetSupportedSRSList(OGRLayerH hLayer,
8413 : int iGeomField, int *pnCount)
8414 : {
8415 4 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSupportedSRSList", nullptr);
8416 4 : VALIDATE_POINTER1(pnCount, "OGR_L_GetSupportedSRSList", nullptr);
8417 :
8418 : const auto &srsList =
8419 4 : OGRLayer::FromHandle(hLayer)->GetSupportedSRSList(iGeomField);
8420 4 : *pnCount = static_cast<int>(srsList.size());
8421 4 : if (srsList.empty())
8422 : {
8423 2 : return nullptr;
8424 : }
8425 : OGRSpatialReferenceH *pahRet = static_cast<OGRSpatialReferenceH *>(
8426 2 : CPLMalloc((1 + srsList.size()) * sizeof(OGRSpatialReferenceH)));
8427 2 : size_t i = 0;
8428 7 : for (const auto &poSRS : srsList)
8429 : {
8430 5 : poSRS->Reference();
8431 5 : pahRet[i] = OGRSpatialReference::ToHandle(poSRS.get());
8432 5 : ++i;
8433 : }
8434 2 : pahRet[i] = nullptr;
8435 2 : return pahRet;
8436 : }
8437 :
8438 : /************************************************************************/
8439 : /* OGRLayer::SetActiveSRS() */
8440 : /************************************************************************/
8441 :
8442 : /** \brief Change the active SRS.
8443 : *
8444 : * The passed SRS must be in the list returned by GetSupportedSRSList()
8445 : * (the actual pointer may be different, but should be tested as identical
8446 : * with OGRSpatialReference::IsSame()).
8447 : *
8448 : * Changing the active SRS affects:
8449 : * <ul>
8450 : * <li>the SRS in which geometries of returned features are expressed,</li>
8451 : * <li>the SRS in which geometries of passed features (CreateFeature(),
8452 : * SetFeature()) are expressed,</li>
8453 : * <li>the SRS returned by GetSpatialRef() and
8454 : * GetGeomFieldDefn()->GetSpatialRef(),</li>
8455 : * <li>the SRS used to interpret SetSpatialFilter() values.</li>
8456 : * </ul>
8457 : * This also resets feature reading and the spatial filter.
8458 : * Note however that this does not modify the storage SRS of the features of
8459 : * geometries. Said otherwise, this setting is volatile and has no persistent
8460 : * effects after dataset reopening.
8461 : *
8462 : * @param iGeomField Geometry field index.
8463 : * @param poSRS SRS to use
8464 : * @return OGRERR_NONE in case of success, or OGRERR_FAILURE if
8465 : * the passed SRS is not in GetSupportedSRSList()
8466 : * @since GDAL 3.7
8467 : */
8468 1 : OGRErr OGRLayer::SetActiveSRS(CPL_UNUSED int iGeomField,
8469 : CPL_UNUSED const OGRSpatialReference *poSRS)
8470 : {
8471 1 : return OGRERR_FAILURE;
8472 : }
8473 :
8474 : /************************************************************************/
8475 : /* OGR_L_SetActiveSRS() */
8476 : /************************************************************************/
8477 :
8478 : /** \brief Change the active SRS.
8479 : *
8480 : * The passed SRS must be in the list returned by GetSupportedSRSList()
8481 : * (the actual pointer may be different, but should be tested as identical
8482 : * with OGRSpatialReference::IsSame()).
8483 : *
8484 : * Changing the active SRS affects:
8485 : * <ul>
8486 : * <li>the SRS in which geometries of returned features are expressed,</li>
8487 : * <li>the SRS in which geometries of passed features (CreateFeature(),
8488 : * SetFeature()) are expressed,</li>
8489 : * <li>the SRS returned by GetSpatialRef() and
8490 : * GetGeomFieldDefn()->GetSpatialRef(),</li>
8491 : * <li>the SRS used to interpret SetSpatialFilter() values.</li>
8492 : * </ul>
8493 : * This also resets feature reading and the spatial filter.
8494 : * Note however that this does not modify the storage SRS of the features of
8495 : * geometries. Said otherwise, this setting is volatile and has no persistent
8496 : * effects after dataset reopening.
8497 : *
8498 : * @param hLayer Layer.
8499 : * @param iGeomField Geometry field index.
8500 : * @param hSRS SRS to use
8501 : * @return OGRERR_NONE in case of success, OGRERR_FAILURE if
8502 : * the passed SRS is not in GetSupportedSRSList().
8503 : * @since GDAL 3.7
8504 : */
8505 9 : OGRErr OGR_L_SetActiveSRS(OGRLayerH hLayer, int iGeomField,
8506 : OGRSpatialReferenceH hSRS)
8507 : {
8508 9 : VALIDATE_POINTER1(hLayer, "OGR_L_SetActiveSRS", OGRERR_FAILURE);
8509 18 : return OGRLayer::FromHandle(hLayer)->SetActiveSRS(
8510 9 : iGeomField, OGRSpatialReference::FromHandle(hSRS));
8511 : }
8512 :
8513 : /************************************************************************/
8514 : /* GetDataset() */
8515 : /************************************************************************/
8516 :
8517 : /** Return the dataset associated with this layer.
8518 : *
8519 : * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
8520 : * have CreateLayer() capability. It may not be implemented in read-only
8521 : * drivers or out-of-tree drivers.
8522 : *
8523 : * It is currently only used by the GetRecordBatchSchema()
8524 : * method to retrieve the field domain associated with a field, to fill the
8525 : * dictionary field of a struct ArrowSchema.
8526 : * It is also used by CreateFieldFromArrowSchema() to determine which field
8527 : * types and subtypes are supported by the layer, by inspecting the driver
8528 : * metadata, and potentially use fallback types when needed.
8529 : *
8530 : * This method is the same as the C function OGR_L_GetDataset().
8531 : *
8532 : * @return dataset, or nullptr when unknown.
8533 : * @since GDAL 3.6
8534 : */
8535 25 : GDALDataset *OGRLayer::GetDataset()
8536 : {
8537 25 : return nullptr;
8538 : }
8539 :
8540 : /************************************************************************/
8541 : /* OGR_L_GetDataset() */
8542 : /************************************************************************/
8543 :
8544 : /** Return the dataset associated with this layer.
8545 : *
8546 : * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
8547 : * have CreateLayer() capability. It may not be implemented in read-only
8548 : * drivers or out-of-tree drivers.
8549 : *
8550 : * It is currently only used by the GetRecordBatchSchema()
8551 : * method to retrieve the field domain associated with a field, to fill the
8552 : * dictionary field of a struct ArrowSchema.
8553 : * It is also used by CreateFieldFromArrowSchema() to determine which field
8554 : * types and subtypes are supported by the layer, by inspecting the driver
8555 : * metadata, and potentially use fallback types when needed.
8556 : *
8557 : * This function is the same as the C++ method OGRLayer::GetDataset().
8558 : *
8559 : * @return dataset, or nullptr when unknown.
8560 : * @since GDAL 3.9
8561 : */
8562 264 : GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
8563 : {
8564 264 : VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
8565 264 : return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
8566 : }
|