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