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 <set>
28 :
29 : /************************************************************************/
30 : /* OGRLayer() */
31 : /************************************************************************/
32 :
33 69112 : OGRLayer::OGRLayer()
34 69112 : : m_poPrivate(new Private()), m_bFilterIsEnvelope(FALSE),
35 : m_poFilterGeom(nullptr),
36 : m_pPreparedFilterGeom(nullptr), m_sFilterEnvelope{},
37 : m_iGeomFieldFilter(0), m_poStyleTable(nullptr), m_poAttrQuery(nullptr),
38 : m_pszAttrQueryString(nullptr), m_poAttrIndex(nullptr), m_nRefCount(0),
39 138224 : m_nFeaturesRead(0)
40 : {
41 69112 : }
42 :
43 : /************************************************************************/
44 : /* ~OGRLayer() */
45 : /************************************************************************/
46 :
47 69095 : OGRLayer::~OGRLayer()
48 :
49 : {
50 69095 : if (m_poStyleTable)
51 : {
52 11 : delete m_poStyleTable;
53 11 : m_poStyleTable = nullptr;
54 : }
55 :
56 69095 : if (m_poAttrIndex != nullptr)
57 : {
58 166 : delete m_poAttrIndex;
59 166 : m_poAttrIndex = nullptr;
60 : }
61 :
62 69095 : if (m_poAttrQuery != nullptr)
63 : {
64 634 : delete m_poAttrQuery;
65 634 : m_poAttrQuery = nullptr;
66 : }
67 :
68 69095 : CPLFree(m_pszAttrQueryString);
69 :
70 69095 : if (m_poFilterGeom)
71 : {
72 864 : delete m_poFilterGeom;
73 864 : m_poFilterGeom = nullptr;
74 : }
75 :
76 69095 : if (m_pPreparedFilterGeom != nullptr)
77 : {
78 864 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
79 864 : m_pPreparedFilterGeom = nullptr;
80 : }
81 :
82 69095 : if (m_poSharedArrowArrayStreamPrivateData != nullptr)
83 : {
84 677 : m_poSharedArrowArrayStreamPrivateData->m_poLayer = nullptr;
85 : }
86 69095 : }
87 :
88 : /************************************************************************/
89 : /* Reference() */
90 : /************************************************************************/
91 :
92 0 : int OGRLayer::Reference()
93 :
94 : {
95 0 : return ++m_nRefCount;
96 : }
97 :
98 : /************************************************************************/
99 : /* OGR_L_Reference() */
100 : /************************************************************************/
101 :
102 0 : int OGR_L_Reference(OGRLayerH hLayer)
103 :
104 : {
105 0 : VALIDATE_POINTER1(hLayer, "OGR_L_Reference", 0);
106 :
107 0 : return OGRLayer::FromHandle(hLayer)->Reference();
108 : }
109 :
110 : /************************************************************************/
111 : /* Dereference() */
112 : /************************************************************************/
113 :
114 0 : int OGRLayer::Dereference()
115 :
116 : {
117 0 : return --m_nRefCount;
118 : }
119 :
120 : /************************************************************************/
121 : /* OGR_L_Dereference() */
122 : /************************************************************************/
123 :
124 0 : int OGR_L_Dereference(OGRLayerH hLayer)
125 :
126 : {
127 0 : VALIDATE_POINTER1(hLayer, "OGR_L_Dereference", 0);
128 :
129 0 : return OGRLayer::FromHandle(hLayer)->Dereference();
130 : }
131 :
132 : /************************************************************************/
133 : /* GetRefCount() */
134 : /************************************************************************/
135 :
136 0 : int OGRLayer::GetRefCount() const
137 :
138 : {
139 0 : return m_nRefCount;
140 : }
141 :
142 : /************************************************************************/
143 : /* OGR_L_GetRefCount() */
144 : /************************************************************************/
145 :
146 0 : int OGR_L_GetRefCount(OGRLayerH hLayer)
147 :
148 : {
149 0 : VALIDATE_POINTER1(hLayer, "OGR_L_GetRefCount", 0);
150 :
151 0 : return OGRLayer::FromHandle(hLayer)->GetRefCount();
152 : }
153 :
154 : /************************************************************************/
155 : /* GetFeatureCount() */
156 : /************************************************************************/
157 :
158 13831 : GIntBig OGRLayer::GetFeatureCount(int bForce)
159 :
160 : {
161 13831 : if (!bForce)
162 1 : return -1;
163 :
164 13830 : GIntBig nFeatureCount = 0;
165 55681 : for (auto &&poFeature : *this)
166 : {
167 41851 : CPL_IGNORE_RET_VAL(poFeature.get());
168 41851 : nFeatureCount++;
169 : }
170 13830 : ResetReading();
171 :
172 13830 : return nFeatureCount;
173 : }
174 :
175 : /************************************************************************/
176 : /* OGR_L_GetFeatureCount() */
177 : /************************************************************************/
178 :
179 36815 : GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
180 :
181 : {
182 36815 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
183 :
184 : #ifdef OGRAPISPY_ENABLED
185 36815 : if (bOGRAPISpyEnabled)
186 2 : OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
187 : #endif
188 :
189 36815 : return OGRLayer::FromHandle(hLayer)->GetFeatureCount(bForce);
190 : }
191 :
192 : /************************************************************************/
193 : /* GetExtent() */
194 : /************************************************************************/
195 :
196 : /**
197 : \brief Fetch the extent of this layer.
198 :
199 : Returns the extent (MBR) of the data in the layer. If bForce is FALSE,
200 : and it would be expensive to establish the extent then OGRERR_FAILURE
201 : will be returned indicating that the extent isn't know. If bForce is
202 : TRUE then some implementations will actually scan the entire layer once
203 : to compute the MBR of all the features in the layer.
204 :
205 : Depending on the drivers, the returned extent may or may not take the
206 : spatial filter into account. So it is safer to call GetExtent() without
207 : setting a spatial filter.
208 :
209 : Layers without any geometry may return OGRERR_FAILURE just indicating that
210 : no meaningful extents could be collected.
211 :
212 : Note that some implementations of this method may alter the read cursor
213 : of the layer.
214 :
215 : This method is the same as the C function OGR_L_GetExtent().
216 :
217 : @param psExtent the structure in which the extent value will be returned.
218 : @param bForce Flag indicating whether the extent should be computed even
219 : if it is expensive.
220 :
221 : @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
222 : */
223 :
224 14994 : OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, bool bForce)
225 : {
226 14994 : return GetExtent(0, psExtent, bForce);
227 : }
228 :
229 : /**
230 : \brief Fetch the extent of this layer, on the specified geometry field.
231 :
232 : Returns the extent (MBR) of the data in the layer. If bForce is FALSE,
233 : and it would be expensive to establish the extent then OGRERR_FAILURE
234 : will be returned indicating that the extent isn't know. If bForce is
235 : TRUE then some implementations will actually scan the entire layer once
236 : to compute the MBR of all the features in the layer.
237 :
238 : Depending on the drivers, the returned extent may or may not take the
239 : spatial filter into account. So it is safer to call GetExtent() without
240 : setting a spatial filter.
241 :
242 : Layers without any geometry may return OGRERR_FAILURE just indicating that
243 : no meaningful extents could be collected.
244 :
245 : Note that some implementations of this method may alter the read cursor
246 : of the layer.
247 :
248 : This method is the same as the C function OGR_L_GetExtentEx().
249 :
250 : @param iGeomField the index of the geometry field on which to compute the extent.
251 : @param psExtent the structure in which the extent value will be returned.
252 : @param bForce Flag indicating whether the extent should be computed even
253 : if it is expensive.
254 :
255 : @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
256 :
257 : */
258 :
259 17073 : OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
260 : {
261 17073 : psExtent->MinX = 0.0;
262 17073 : psExtent->MaxX = 0.0;
263 17073 : psExtent->MinY = 0.0;
264 17073 : psExtent->MaxY = 0.0;
265 :
266 : /* -------------------------------------------------------------------- */
267 : /* If this layer has a none geometry type, then we can */
268 : /* reasonably assume there are not extents available. */
269 : /* -------------------------------------------------------------------- */
270 33372 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
271 16299 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
272 : {
273 774 : if (iGeomField != 0)
274 : {
275 608 : CPLError(CE_Failure, CPLE_AppDefined,
276 : "Invalid geometry field index : %d", iGeomField);
277 : }
278 774 : return OGRERR_FAILURE;
279 : }
280 :
281 16299 : return IGetExtent(iGeomField, psExtent, bForce);
282 : }
283 :
284 : /************************************************************************/
285 : /* IGetExtent() */
286 : /************************************************************************/
287 :
288 : /**
289 : \brief Fetch the extent of this layer, on the specified geometry field.
290 :
291 : Virtual method implemented by drivers since 3.11. In previous versions,
292 : GetExtent() itself was the virtual method.
293 :
294 : Driver implementations, when wanting to call the base method, must take
295 : care of calling OGRLayer::IGetExtent() (and note the public method without
296 : the leading I).
297 :
298 : @param iGeomField 0-based index of the geometry field to consider.
299 : @param psExtent the computed extent of the layer.
300 : @param bForce if TRUE, the extent will be computed even if all the
301 : layer features have to be fetched.
302 : @return OGRERR_NONE on success or an error code in case of failure.
303 : @since GDAL 3.11
304 : */
305 :
306 415 : OGRErr OGRLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
307 :
308 : {
309 : /* -------------------------------------------------------------------- */
310 : /* If not forced, we should avoid having to scan all the */
311 : /* features and just return a failure. */
312 : /* -------------------------------------------------------------------- */
313 415 : if (!bForce)
314 1 : return OGRERR_FAILURE;
315 :
316 : /* -------------------------------------------------------------------- */
317 : /* OK, we hate to do this, but go ahead and read through all */
318 : /* the features to collect geometries and build extents. */
319 : /* -------------------------------------------------------------------- */
320 414 : OGREnvelope oEnv;
321 414 : bool bExtentSet = false;
322 :
323 9582 : for (auto &&poFeature : *this)
324 : {
325 9168 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
326 9168 : if (poGeom == nullptr || poGeom->IsEmpty())
327 : {
328 : /* Do nothing */
329 : }
330 8863 : else if (!bExtentSet)
331 : {
332 364 : poGeom->getEnvelope(psExtent);
333 728 : if (!(std::isnan(psExtent->MinX) || std::isnan(psExtent->MinY) ||
334 364 : std::isnan(psExtent->MaxX) || std::isnan(psExtent->MaxY)))
335 : {
336 364 : bExtentSet = true;
337 : }
338 : }
339 : else
340 : {
341 8499 : poGeom->getEnvelope(&oEnv);
342 8499 : if (oEnv.MinX < psExtent->MinX)
343 301 : psExtent->MinX = oEnv.MinX;
344 8499 : if (oEnv.MinY < psExtent->MinY)
345 440 : psExtent->MinY = oEnv.MinY;
346 8499 : if (oEnv.MaxX > psExtent->MaxX)
347 877 : psExtent->MaxX = oEnv.MaxX;
348 8499 : if (oEnv.MaxY > psExtent->MaxY)
349 851 : psExtent->MaxY = oEnv.MaxY;
350 : }
351 : }
352 414 : ResetReading();
353 :
354 414 : return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
355 : }
356 :
357 : /************************************************************************/
358 : /* OGR_L_GetExtent() */
359 : /************************************************************************/
360 :
361 : /**
362 : \brief Fetch the extent of this layer.
363 :
364 : Returns the extent (MBR) of the data in the layer. If bForce is FALSE,
365 : and it would be expensive to establish the extent then OGRERR_FAILURE
366 : will be returned indicating that the extent isn't know. If bForce is
367 : TRUE then some implementations will actually scan the entire layer once
368 : to compute the MBR of all the features in the layer.
369 :
370 : Depending on the drivers, the returned extent may or may not take the
371 : spatial filter into account. So it is safer to call OGR_L_GetExtent() without
372 : setting a spatial filter.
373 :
374 : Layers without any geometry may return OGRERR_FAILURE just indicating that
375 : no meaningful extents could be collected.
376 :
377 : Note that some implementations of this method may alter the read cursor
378 : of the layer.
379 :
380 : This function is the same as the C++ method OGRLayer::GetExtent().
381 :
382 : @param hLayer handle to the layer from which to get extent.
383 : @param psExtent the structure in which the extent value will be returned.
384 : @param bForce Flag indicating whether the extent should be computed even
385 : if it is expensive.
386 :
387 : @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
388 :
389 : */
390 :
391 60 : OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
392 :
393 : {
394 60 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
395 :
396 : #ifdef OGRAPISPY_ENABLED
397 60 : if (bOGRAPISpyEnabled)
398 0 : OGRAPISpy_L_GetExtent(hLayer, bForce);
399 : #endif
400 :
401 60 : return OGRLayer::FromHandle(hLayer)->GetExtent(0, psExtent,
402 60 : bForce != FALSE);
403 : }
404 :
405 : /************************************************************************/
406 : /* OGR_L_GetExtentEx() */
407 : /************************************************************************/
408 :
409 : /**
410 : \brief Fetch the extent of this layer, on the specified geometry field.
411 :
412 : Returns the extent (MBR) of the data in the layer. If bForce is FALSE,
413 : and it would be expensive to establish the extent then OGRERR_FAILURE
414 : will be returned indicating that the extent isn't know. If bForce is
415 : TRUE then some implementations will actually scan the entire layer once
416 : to compute the MBR of all the features in the layer.
417 :
418 : Depending on the drivers, the returned extent may or may not take the
419 : spatial filter into account. So it is safer to call OGR_L_GetExtent() without
420 : setting a spatial filter.
421 :
422 : Layers without any geometry may return OGRERR_FAILURE just indicating that
423 : no meaningful extents could be collected.
424 :
425 : Note that some implementations of this method may alter the read cursor
426 : of the layer.
427 :
428 : This function is the same as the C++ method OGRLayer::GetExtent().
429 :
430 : @param hLayer handle to the layer from which to get extent.
431 : @param iGeomField the index of the geometry field on which to compute the extent.
432 : @param psExtent the structure in which the extent value will be returned.
433 : @param bForce Flag indicating whether the extent should be computed even
434 : if it is expensive.
435 :
436 : @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
437 :
438 : */
439 372 : OGRErr OGR_L_GetExtentEx(OGRLayerH hLayer, int iGeomField,
440 : OGREnvelope *psExtent, int bForce)
441 :
442 : {
443 372 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE);
444 :
445 : #ifdef OGRAPISPY_ENABLED
446 372 : if (bOGRAPISpyEnabled)
447 4 : OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
448 : #endif
449 :
450 372 : return OGRLayer::FromHandle(hLayer)->GetExtent(iGeomField, psExtent,
451 372 : bForce != FALSE);
452 : }
453 :
454 : /************************************************************************/
455 : /* GetExtent3D() */
456 : /************************************************************************/
457 :
458 : /**
459 : \brief Fetch the 3D extent of this layer, on the specified geometry field.
460 :
461 : Returns the 3D extent (MBR) of the data in the layer. If bForce is FALSE,
462 : and it would be expensive to establish the extent then OGRERR_FAILURE
463 : will be returned indicating that the extent isn't know. If bForce is
464 : TRUE then some implementations will actually scan the entire layer once
465 : to compute the MBR of all the features in the layer.
466 :
467 : (Contrarty to GetExtent() 2D), the returned extent will always take into
468 : account the attribute and spatial filters that may be installed.
469 :
470 : Layers without any geometry may return OGRERR_FAILURE just indicating that
471 : no meaningful extents could be collected.
472 :
473 : For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
474 : fields will be respectively set to +Infinity and -Infinity.
475 :
476 : Note that some implementations of this method may alter the read cursor
477 : of the layer.
478 :
479 : This function is the same as the C function OGR_L_GetExtent3D().
480 :
481 : @param iGeomField 0-based index of the geometry field to consider.
482 : @param psExtent3D the computed 3D extent of the layer.
483 : @param bForce if TRUE, the extent will be computed even if all the
484 : layer features have to be fetched.
485 : @return OGRERR_NONE on success or an error code in case of failure.
486 : @since GDAL 3.9
487 : */
488 :
489 65 : OGRErr OGRLayer::GetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
490 : bool bForce)
491 :
492 : {
493 65 : psExtent3D->MinX = 0.0;
494 65 : psExtent3D->MaxX = 0.0;
495 65 : psExtent3D->MinY = 0.0;
496 65 : psExtent3D->MaxY = 0.0;
497 65 : psExtent3D->MinZ = std::numeric_limits<double>::infinity();
498 65 : psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
499 :
500 : /* -------------------------------------------------------------------- */
501 : /* If this layer has a none geometry type, then we can */
502 : /* reasonably assume there are not extents available. */
503 : /* -------------------------------------------------------------------- */
504 129 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
505 64 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
506 : {
507 1 : if (iGeomField != 0)
508 : {
509 0 : CPLError(CE_Failure, CPLE_AppDefined,
510 : "Invalid geometry field index : %d", iGeomField);
511 : }
512 1 : return OGRERR_FAILURE;
513 : }
514 :
515 64 : return IGetExtent3D(iGeomField, psExtent3D, bForce);
516 : }
517 :
518 : /************************************************************************/
519 : /* IGetExtent3D() */
520 : /************************************************************************/
521 :
522 : /**
523 : \brief Fetch the 3D extent of this layer, on the specified geometry field.
524 :
525 : See GetExtent3D() documentation.
526 :
527 : Virtual method implemented by drivers since 3.11. In previous versions,
528 : GetExtent3D() itself was the virtual method.
529 :
530 : Driver implementations, when wanting to call the base method, must take
531 : care of calling OGRLayer::IGetExtent3D() (and note the public method without
532 : the leading I).
533 :
534 : @param iGeomField 0-based index of the geometry field to consider.
535 : @param psExtent3D the computed 3D extent of the layer.
536 : @param bForce if TRUE, the extent will be computed even if all the
537 : layer features have to be fetched.
538 : @return OGRERR_NONE on success or an error code in case of failure.
539 : @since GDAL 3.11
540 : */
541 :
542 27 : OGRErr OGRLayer::IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
543 : bool bForce)
544 :
545 : {
546 : /* -------------------------------------------------------------------- */
547 : /* If not forced, we should avoid having to scan all the */
548 : /* features and just return a failure. */
549 : /* -------------------------------------------------------------------- */
550 27 : if (!bForce)
551 0 : return OGRERR_FAILURE;
552 :
553 : /* -------------------------------------------------------------------- */
554 : /* OK, we hate to do this, but go ahead and read through all */
555 : /* the features to collect geometries and build extents. */
556 : /* -------------------------------------------------------------------- */
557 27 : OGREnvelope3D oEnv;
558 27 : bool bExtentSet = false;
559 :
560 133 : for (auto &&poFeature : *this)
561 : {
562 106 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
563 106 : if (poGeom == nullptr || poGeom->IsEmpty())
564 : {
565 : /* Do nothing */
566 : }
567 89 : else if (!bExtentSet)
568 : {
569 27 : poGeom->getEnvelope(psExtent3D);
570 : // This is required because getEnvelope initializes Z to 0 for 2D geometries
571 27 : if (!poGeom->Is3D())
572 : {
573 20 : psExtent3D->MinZ = std::numeric_limits<double>::infinity();
574 20 : psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
575 : }
576 27 : bExtentSet = true;
577 : }
578 : else
579 : {
580 62 : poGeom->getEnvelope(&oEnv);
581 : // This is required because getEnvelope initializes Z to 0 for 2D geometries
582 62 : if (!poGeom->Is3D())
583 : {
584 53 : oEnv.MinZ = std::numeric_limits<double>::infinity();
585 53 : oEnv.MaxZ = -std::numeric_limits<double>::infinity();
586 : }
587 : // Merge handles infinity correctly
588 62 : psExtent3D->Merge(oEnv);
589 : }
590 : }
591 27 : ResetReading();
592 :
593 27 : return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
594 : }
595 :
596 : /************************************************************************/
597 : /* OGR_L_GetExtent3D() */
598 : /************************************************************************/
599 :
600 : /**
601 : \brief Fetch the 3D extent of this layer, on the specified geometry field.
602 :
603 : Returns the 3D extent (MBR) of the data in the layer. If bForce is FALSE,
604 : and it would be expensive to establish the extent then OGRERR_FAILURE
605 : will be returned indicating that the extent isn't know. If bForce is
606 : TRUE then some implementations will actually scan the entire layer once
607 : to compute the MBR of all the features in the layer.
608 :
609 : (Contrarty to GetExtent() 2D), the returned extent will always take into
610 : account the attribute and spatial filters that may be installed.
611 :
612 : Layers without any geometry may return OGRERR_FAILURE just indicating that
613 : no meaningful extents could be collected.
614 :
615 : For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
616 : fields will be respectively set to +Infinity and -Infinity.
617 :
618 : Note that some implementations of this method may alter the read cursor
619 : of the layer.
620 :
621 : This function is the same as the C++ method OGRLayer::GetExtent3D().
622 :
623 : @param hLayer the layer to consider.
624 : @param iGeomField 0-based index of the geometry field to consider.
625 : @param psExtent3D the computed 3D extent of the layer.
626 : @param bForce if TRUE, the extent will be computed even if all the
627 : layer features have to be fetched.
628 : @return OGRERR_NONE on success or an error code in case of failure.
629 : @since GDAL 3.9
630 : */
631 :
632 60 : OGRErr OGR_L_GetExtent3D(OGRLayerH hLayer, int iGeomField,
633 : OGREnvelope3D *psExtent3D, int bForce)
634 :
635 : {
636 60 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent3D", OGRERR_INVALID_HANDLE);
637 :
638 : #ifdef OGRAPISPY_ENABLED
639 60 : if (bOGRAPISpyEnabled)
640 0 : OGRAPISpy_L_GetExtent3D(hLayer, iGeomField, bForce);
641 : #endif
642 :
643 60 : return OGRLayer::FromHandle(hLayer)->GetExtent3D(iGeomField, psExtent3D,
644 60 : bForce != FALSE);
645 : }
646 :
647 : /************************************************************************/
648 : /* SetAttributeFilter() */
649 : /************************************************************************/
650 :
651 14805 : OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
652 :
653 : {
654 14805 : CPLFree(m_pszAttrQueryString);
655 14805 : m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
656 :
657 : /* -------------------------------------------------------------------- */
658 : /* Are we just clearing any existing query? */
659 : /* -------------------------------------------------------------------- */
660 14805 : if (pszQuery == nullptr || strlen(pszQuery) == 0)
661 : {
662 9827 : if (m_poAttrQuery)
663 : {
664 2834 : delete m_poAttrQuery;
665 2834 : m_poAttrQuery = nullptr;
666 2834 : ResetReading();
667 : }
668 9827 : return OGRERR_NONE;
669 : }
670 :
671 : /* -------------------------------------------------------------------- */
672 : /* Or are we installing a new query? */
673 : /* -------------------------------------------------------------------- */
674 : OGRErr eErr;
675 :
676 4978 : if (!m_poAttrQuery)
677 3527 : m_poAttrQuery = new OGRFeatureQuery();
678 :
679 4978 : eErr = m_poAttrQuery->Compile(this, pszQuery);
680 4978 : if (eErr != OGRERR_NONE)
681 : {
682 3 : delete m_poAttrQuery;
683 3 : m_poAttrQuery = nullptr;
684 : }
685 :
686 4978 : ResetReading();
687 :
688 4978 : return eErr;
689 : }
690 :
691 : /************************************************************************/
692 : /* ContainGeomSpecialField() */
693 : /************************************************************************/
694 :
695 274 : static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
696 : {
697 274 : if (expr->eNodeType == SNT_COLUMN)
698 : {
699 57 : if (expr->table_index == 0 && expr->field_index != -1)
700 : {
701 57 : int nSpecialFieldIdx = expr->field_index - nLayerFieldCount;
702 57 : return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
703 114 : nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
704 57 : nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
705 : }
706 : }
707 217 : else if (expr->eNodeType == SNT_OPERATION)
708 : {
709 327 : for (int i = 0; i < expr->nSubExprCount; i++)
710 : {
711 214 : if (ContainGeomSpecialField(expr->papoSubExpr[i], nLayerFieldCount))
712 0 : return TRUE;
713 : }
714 : }
715 217 : return FALSE;
716 : }
717 :
718 : /************************************************************************/
719 : /* AttributeFilterEvaluationNeedsGeometry() */
720 : /************************************************************************/
721 :
722 : //! @cond Doxygen_Suppress
723 60 : int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
724 : {
725 60 : if (!m_poAttrQuery)
726 0 : return FALSE;
727 :
728 : swq_expr_node *expr =
729 60 : static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
730 60 : int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
731 :
732 60 : return ContainGeomSpecialField(expr, nLayerFieldCount);
733 : }
734 :
735 : //! @endcond
736 :
737 : /************************************************************************/
738 : /* OGR_L_SetAttributeFilter() */
739 : /************************************************************************/
740 :
741 1446 : OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszQuery)
742 :
743 : {
744 1446 : VALIDATE_POINTER1(hLayer, "OGR_L_SetAttributeFilter",
745 : OGRERR_INVALID_HANDLE);
746 :
747 : #ifdef OGRAPISPY_ENABLED
748 1446 : if (bOGRAPISpyEnabled)
749 4 : OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
750 : #endif
751 :
752 1446 : return OGRLayer::FromHandle(hLayer)->SetAttributeFilter(pszQuery);
753 : }
754 :
755 : /************************************************************************/
756 : /* GetFeature() */
757 : /************************************************************************/
758 :
759 984 : OGRFeature *OGRLayer::GetFeature(GIntBig nFID)
760 :
761 : {
762 : /* Save old attribute and spatial filters */
763 : char *pszOldFilter =
764 984 : m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
765 : OGRGeometry *poOldFilterGeom =
766 984 : (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr;
767 984 : int iOldGeomFieldFilter = m_iGeomFieldFilter;
768 : /* Unset filters */
769 984 : SetAttributeFilter(nullptr);
770 984 : SetSpatialFilter(0, nullptr);
771 :
772 984 : OGRFeatureUniquePtr poFeature;
773 14391 : for (auto &&poFeatureIter : *this)
774 : {
775 13407 : if (poFeatureIter->GetFID() == nFID)
776 : {
777 660 : poFeature.swap(poFeatureIter);
778 660 : break;
779 : }
780 : }
781 :
782 : /* Restore filters */
783 984 : SetAttributeFilter(pszOldFilter);
784 984 : CPLFree(pszOldFilter);
785 984 : SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
786 984 : delete poOldFilterGeom;
787 :
788 1968 : return poFeature.release();
789 : }
790 :
791 : /************************************************************************/
792 : /* OGR_L_GetFeature() */
793 : /************************************************************************/
794 :
795 2534 : OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
796 :
797 : {
798 2534 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
799 :
800 : #ifdef OGRAPISPY_ENABLED
801 2534 : if (bOGRAPISpyEnabled)
802 2 : OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
803 : #endif
804 :
805 2534 : return OGRFeature::ToHandle(
806 5068 : OGRLayer::FromHandle(hLayer)->GetFeature(nFeatureId));
807 : }
808 :
809 : /************************************************************************/
810 : /* SetNextByIndex() */
811 : /************************************************************************/
812 :
813 1075 : OGRErr OGRLayer::SetNextByIndex(GIntBig nIndex)
814 :
815 : {
816 1075 : if (nIndex < 0)
817 194 : return OGRERR_FAILURE;
818 :
819 881 : ResetReading();
820 :
821 881 : OGRFeature *poFeature = nullptr;
822 129350 : while (nIndex-- > 0)
823 : {
824 128663 : poFeature = GetNextFeature();
825 128663 : if (poFeature == nullptr)
826 194 : return OGRERR_FAILURE;
827 :
828 128469 : delete poFeature;
829 : }
830 :
831 687 : return OGRERR_NONE;
832 : }
833 :
834 : /************************************************************************/
835 : /* OGR_L_SetNextByIndex() */
836 : /************************************************************************/
837 :
838 39 : OGRErr OGR_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
839 :
840 : {
841 39 : VALIDATE_POINTER1(hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE);
842 :
843 : #ifdef OGRAPISPY_ENABLED
844 39 : if (bOGRAPISpyEnabled)
845 2 : OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
846 : #endif
847 :
848 39 : return OGRLayer::FromHandle(hLayer)->SetNextByIndex(nIndex);
849 : }
850 :
851 : /************************************************************************/
852 : /* OGR_L_GetNextFeature() */
853 : /************************************************************************/
854 :
855 83114 : OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
856 :
857 : {
858 83114 : VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
859 :
860 : #ifdef OGRAPISPY_ENABLED
861 83114 : if (bOGRAPISpyEnabled)
862 8 : OGRAPISpy_L_GetNextFeature(hLayer);
863 : #endif
864 :
865 83114 : return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
866 : }
867 :
868 : /************************************************************************/
869 : /* ConvertGeomsIfNecessary() */
870 : /************************************************************************/
871 :
872 938087 : void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
873 : {
874 938087 : if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
875 : {
876 : // One time initialization
877 8994 : m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
878 8994 : m_poPrivate->m_bSupportsCurve =
879 8994 : CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
880 8994 : m_poPrivate->m_bSupportsM =
881 8994 : CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
882 8994 : if (CPLTestBool(
883 : CPLGetConfigOption("OGR_APPLY_GEOM_SET_PRECISION", "FALSE")))
884 : {
885 2 : const auto poFeatureDefn = GetLayerDefn();
886 2 : const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
887 2 : for (int i = 0; i < nGeomFieldCount; i++)
888 : {
889 2 : const double dfXYResolution = poFeatureDefn->GetGeomFieldDefn(i)
890 2 : ->GetCoordinatePrecision()
891 2 : .dfXYResolution;
892 4 : if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
893 2 : OGRGeometryFactory::haveGEOS())
894 : {
895 2 : m_poPrivate->m_bApplyGeomSetPrecision = true;
896 2 : break;
897 : }
898 : }
899 : }
900 : }
901 :
902 1787450 : if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
903 849365 : m_poPrivate->m_bApplyGeomSetPrecision)
904 : {
905 88724 : const auto poFeatureDefn = GetLayerDefn();
906 88724 : const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
907 176756 : for (int i = 0; i < nGeomFieldCount; i++)
908 : {
909 88032 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
910 88032 : if (poGeom)
911 : {
912 103818 : if (!m_poPrivate->m_bSupportsM &&
913 18752 : OGR_GT_HasM(poGeom->getGeometryType()))
914 : {
915 1 : poGeom->setMeasured(FALSE);
916 : }
917 :
918 169935 : if (!m_poPrivate->m_bSupportsCurve &&
919 84869 : OGR_GT_IsNonLinear(poGeom->getGeometryType()))
920 : {
921 : OGRwkbGeometryType eTargetType =
922 23 : OGR_GT_GetLinear(poGeom->getGeometryType());
923 23 : poGeom = OGRGeometryFactory::forceTo(
924 : poFeature->StealGeometry(i), eTargetType);
925 23 : poFeature->SetGeomFieldDirectly(i, poGeom);
926 23 : poGeom = poFeature->GetGeomFieldRef(i);
927 : }
928 :
929 85066 : if (poGeom && m_poPrivate->m_bApplyGeomSetPrecision)
930 : {
931 : const double dfXYResolution =
932 2 : poFeatureDefn->GetGeomFieldDefn(i)
933 2 : ->GetCoordinatePrecision()
934 2 : .dfXYResolution;
935 4 : if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
936 2 : !poGeom->hasCurveGeometry())
937 : {
938 2 : auto poNewGeom = poGeom->SetPrecision(dfXYResolution,
939 : /* nFlags = */ 0);
940 2 : if (poNewGeom)
941 : {
942 2 : poFeature->SetGeomFieldDirectly(i, poNewGeom);
943 : // If there was potential further processing...
944 : // poGeom = poFeature->GetGeomFieldRef(i);
945 : }
946 : }
947 : }
948 : }
949 : }
950 : }
951 938087 : }
952 :
953 : /************************************************************************/
954 : /* SetFeature() */
955 : /************************************************************************/
956 :
957 3564 : OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
958 :
959 : {
960 3564 : ConvertGeomsIfNecessary(poFeature);
961 3564 : return ISetFeature(poFeature);
962 : }
963 :
964 : /************************************************************************/
965 : /* ISetFeature() */
966 : /************************************************************************/
967 :
968 144 : OGRErr OGRLayer::ISetFeature(OGRFeature *)
969 :
970 : {
971 144 : return OGRERR_UNSUPPORTED_OPERATION;
972 : }
973 :
974 : /************************************************************************/
975 : /* OGR_L_SetFeature() */
976 : /************************************************************************/
977 :
978 2478 : OGRErr OGR_L_SetFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
979 :
980 : {
981 2478 : VALIDATE_POINTER1(hLayer, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
982 2478 : VALIDATE_POINTER1(hFeat, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
983 :
984 : #ifdef OGRAPISPY_ENABLED
985 2478 : if (bOGRAPISpyEnabled)
986 2 : OGRAPISpy_L_SetFeature(hLayer, hFeat);
987 : #endif
988 :
989 2478 : return OGRLayer::FromHandle(hLayer)->SetFeature(
990 2478 : OGRFeature::FromHandle(hFeat));
991 : }
992 :
993 : /************************************************************************/
994 : /* CreateFeature() */
995 : /************************************************************************/
996 :
997 934416 : OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
998 :
999 : {
1000 934416 : ConvertGeomsIfNecessary(poFeature);
1001 934416 : return ICreateFeature(poFeature);
1002 : }
1003 :
1004 : /************************************************************************/
1005 : /* ICreateFeature() */
1006 : /************************************************************************/
1007 :
1008 0 : OGRErr OGRLayer::ICreateFeature(OGRFeature *)
1009 :
1010 : {
1011 0 : return OGRERR_UNSUPPORTED_OPERATION;
1012 : }
1013 :
1014 : /************************************************************************/
1015 : /* OGR_L_CreateFeature() */
1016 : /************************************************************************/
1017 :
1018 286381 : OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1019 :
1020 : {
1021 286381 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1022 286381 : VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1023 :
1024 : #ifdef OGRAPISPY_ENABLED
1025 286381 : if (bOGRAPISpyEnabled)
1026 5 : OGRAPISpy_L_CreateFeature(hLayer, hFeat);
1027 : #endif
1028 :
1029 286381 : return OGRLayer::FromHandle(hLayer)->CreateFeature(
1030 286381 : OGRFeature::FromHandle(hFeat));
1031 : }
1032 :
1033 : /************************************************************************/
1034 : /* UpsertFeature() */
1035 : /************************************************************************/
1036 :
1037 32 : OGRErr OGRLayer::UpsertFeature(OGRFeature *poFeature)
1038 :
1039 : {
1040 32 : ConvertGeomsIfNecessary(poFeature);
1041 32 : return IUpsertFeature(poFeature);
1042 : }
1043 :
1044 : /************************************************************************/
1045 : /* IUpsertFeature() */
1046 : /************************************************************************/
1047 :
1048 0 : OGRErr OGRLayer::IUpsertFeature(OGRFeature *)
1049 : {
1050 0 : return OGRERR_UNSUPPORTED_OPERATION;
1051 : }
1052 :
1053 : /************************************************************************/
1054 : /* OGR_L_UpsertFeature() */
1055 : /************************************************************************/
1056 :
1057 31 : OGRErr OGR_L_UpsertFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1058 :
1059 : {
1060 31 : VALIDATE_POINTER1(hLayer, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
1061 31 : VALIDATE_POINTER1(hFeat, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
1062 :
1063 : #ifdef OGRAPISPY_ENABLED
1064 31 : if (bOGRAPISpyEnabled)
1065 0 : OGRAPISpy_L_UpsertFeature(hLayer, hFeat);
1066 : #endif
1067 :
1068 31 : return OGRLayer::FromHandle(hLayer)->UpsertFeature(
1069 31 : OGRFeature::FromHandle(hFeat));
1070 : }
1071 :
1072 : /************************************************************************/
1073 : /* UpdateFeature() */
1074 : /************************************************************************/
1075 :
1076 75 : OGRErr OGRLayer::UpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
1077 : const int *panUpdatedFieldsIdx,
1078 : int nUpdatedGeomFieldsCount,
1079 : const int *panUpdatedGeomFieldsIdx,
1080 : bool bUpdateStyleString)
1081 :
1082 : {
1083 75 : ConvertGeomsIfNecessary(poFeature);
1084 75 : const int nFieldCount = GetLayerDefn()->GetFieldCount();
1085 136 : for (int i = 0; i < nUpdatedFieldsCount; ++i)
1086 : {
1087 63 : if (panUpdatedFieldsIdx[i] < 0 || panUpdatedFieldsIdx[i] >= nFieldCount)
1088 : {
1089 2 : CPLError(CE_Failure, CPLE_AppDefined,
1090 : "Invalid panUpdatedFieldsIdx[%d] = %d", i,
1091 2 : panUpdatedFieldsIdx[i]);
1092 2 : return OGRERR_FAILURE;
1093 : }
1094 : }
1095 73 : const int nGeomFieldCount = GetLayerDefn()->GetGeomFieldCount();
1096 83 : for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
1097 : {
1098 12 : if (panUpdatedGeomFieldsIdx[i] < 0 ||
1099 11 : panUpdatedGeomFieldsIdx[i] >= nGeomFieldCount)
1100 : {
1101 2 : CPLError(CE_Failure, CPLE_AppDefined,
1102 : "Invalid panUpdatedGeomFieldsIdx[%d] = %d", i,
1103 2 : panUpdatedGeomFieldsIdx[i]);
1104 2 : return OGRERR_FAILURE;
1105 : }
1106 : }
1107 71 : return IUpdateFeature(poFeature, nUpdatedFieldsCount, panUpdatedFieldsIdx,
1108 : nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx,
1109 71 : bUpdateStyleString);
1110 : }
1111 :
1112 : /************************************************************************/
1113 : /* IUpdateFeature() */
1114 : /************************************************************************/
1115 :
1116 28 : OGRErr OGRLayer::IUpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
1117 : const int *panUpdatedFieldsIdx,
1118 : int nUpdatedGeomFieldsCount,
1119 : const int *panUpdatedGeomFieldsIdx,
1120 : bool bUpdateStyleString)
1121 : {
1122 28 : if (!TestCapability(OLCRandomWrite))
1123 0 : return OGRERR_UNSUPPORTED_OPERATION;
1124 :
1125 : auto poFeatureExisting =
1126 56 : std::unique_ptr<OGRFeature>(GetFeature(poFeature->GetFID()));
1127 28 : if (!poFeatureExisting)
1128 1 : return OGRERR_NON_EXISTING_FEATURE;
1129 :
1130 52 : for (int i = 0; i < nUpdatedFieldsCount; ++i)
1131 : {
1132 25 : poFeatureExisting->SetField(
1133 25 : panUpdatedFieldsIdx[i],
1134 25 : poFeature->GetRawFieldRef(panUpdatedFieldsIdx[i]));
1135 : }
1136 29 : for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
1137 : {
1138 2 : poFeatureExisting->SetGeomFieldDirectly(
1139 2 : panUpdatedGeomFieldsIdx[i],
1140 2 : poFeature->StealGeometry(panUpdatedGeomFieldsIdx[i]));
1141 : }
1142 27 : if (bUpdateStyleString)
1143 : {
1144 0 : poFeatureExisting->SetStyleString(poFeature->GetStyleString());
1145 : }
1146 27 : return ISetFeature(poFeatureExisting.get());
1147 : }
1148 :
1149 : /************************************************************************/
1150 : /* OGR_L_UpdateFeature() */
1151 : /************************************************************************/
1152 :
1153 31 : OGRErr OGR_L_UpdateFeature(OGRLayerH hLayer, OGRFeatureH hFeat,
1154 : int nUpdatedFieldsCount,
1155 : const int *panUpdatedFieldsIdx,
1156 : int nUpdatedGeomFieldsCount,
1157 : const int *panUpdatedGeomFieldsIdx,
1158 : bool bUpdateStyleString)
1159 :
1160 : {
1161 31 : VALIDATE_POINTER1(hLayer, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
1162 31 : VALIDATE_POINTER1(hFeat, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
1163 :
1164 31 : return OGRLayer::FromHandle(hLayer)->UpdateFeature(
1165 : OGRFeature::FromHandle(hFeat), nUpdatedFieldsCount, panUpdatedFieldsIdx,
1166 31 : nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx, bUpdateStyleString);
1167 : }
1168 :
1169 : /************************************************************************/
1170 : /* CreateField() */
1171 : /************************************************************************/
1172 :
1173 80 : OGRErr OGRLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
1174 :
1175 : {
1176 : (void)poField;
1177 : (void)bApproxOK;
1178 :
1179 80 : CPLError(CE_Failure, CPLE_NotSupported,
1180 : "CreateField() not supported by this layer.\n");
1181 :
1182 80 : return OGRERR_UNSUPPORTED_OPERATION;
1183 : }
1184 :
1185 : /************************************************************************/
1186 : /* OGR_L_CreateField() */
1187 : /************************************************************************/
1188 :
1189 77294 : OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
1190 :
1191 : {
1192 77294 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1193 77294 : VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1194 :
1195 : #ifdef OGRAPISPY_ENABLED
1196 77294 : if (bOGRAPISpyEnabled)
1197 6 : OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
1198 : #endif
1199 :
1200 154588 : return OGRLayer::FromHandle(hLayer)->CreateField(
1201 77294 : OGRFieldDefn::FromHandle(hField), bApproxOK);
1202 : }
1203 :
1204 : /************************************************************************/
1205 : /* DeleteField() */
1206 : /************************************************************************/
1207 :
1208 0 : OGRErr OGRLayer::DeleteField(int iField)
1209 :
1210 : {
1211 : (void)iField;
1212 :
1213 0 : CPLError(CE_Failure, CPLE_NotSupported,
1214 : "DeleteField() not supported by this layer.\n");
1215 :
1216 0 : return OGRERR_UNSUPPORTED_OPERATION;
1217 : }
1218 :
1219 : /************************************************************************/
1220 : /* OGR_L_DeleteField() */
1221 : /************************************************************************/
1222 :
1223 372 : OGRErr OGR_L_DeleteField(OGRLayerH hLayer, int iField)
1224 :
1225 : {
1226 372 : VALIDATE_POINTER1(hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE);
1227 :
1228 : #ifdef OGRAPISPY_ENABLED
1229 372 : if (bOGRAPISpyEnabled)
1230 2 : OGRAPISpy_L_DeleteField(hLayer, iField);
1231 : #endif
1232 :
1233 372 : return OGRLayer::FromHandle(hLayer)->DeleteField(iField);
1234 : }
1235 :
1236 : /************************************************************************/
1237 : /* ReorderFields() */
1238 : /************************************************************************/
1239 :
1240 0 : OGRErr OGRLayer::ReorderFields(int *panMap)
1241 :
1242 : {
1243 : (void)panMap;
1244 :
1245 0 : CPLError(CE_Failure, CPLE_NotSupported,
1246 : "ReorderFields() not supported by this layer.\n");
1247 :
1248 0 : return OGRERR_UNSUPPORTED_OPERATION;
1249 : }
1250 :
1251 : /************************************************************************/
1252 : /* OGR_L_ReorderFields() */
1253 : /************************************************************************/
1254 :
1255 43 : OGRErr OGR_L_ReorderFields(OGRLayerH hLayer, int *panMap)
1256 :
1257 : {
1258 43 : VALIDATE_POINTER1(hLayer, "OGR_L_ReorderFields", OGRERR_INVALID_HANDLE);
1259 :
1260 : #ifdef OGRAPISPY_ENABLED
1261 43 : if (bOGRAPISpyEnabled)
1262 2 : OGRAPISpy_L_ReorderFields(hLayer, panMap);
1263 : #endif
1264 :
1265 43 : return OGRLayer::FromHandle(hLayer)->ReorderFields(panMap);
1266 : }
1267 :
1268 : /************************************************************************/
1269 : /* ReorderField() */
1270 : /************************************************************************/
1271 :
1272 34 : OGRErr OGRLayer::ReorderField(int iOldFieldPos, int iNewFieldPos)
1273 :
1274 : {
1275 : OGRErr eErr;
1276 :
1277 34 : int nFieldCount = GetLayerDefn()->GetFieldCount();
1278 :
1279 34 : if (iOldFieldPos < 0 || iOldFieldPos >= nFieldCount)
1280 : {
1281 0 : CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
1282 0 : return OGRERR_FAILURE;
1283 : }
1284 34 : if (iNewFieldPos < 0 || iNewFieldPos >= nFieldCount)
1285 : {
1286 0 : CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
1287 0 : return OGRERR_FAILURE;
1288 : }
1289 34 : if (iNewFieldPos == iOldFieldPos)
1290 0 : return OGRERR_NONE;
1291 :
1292 34 : int *panMap = static_cast<int *>(CPLMalloc(sizeof(int) * nFieldCount));
1293 34 : if (iOldFieldPos < iNewFieldPos)
1294 : {
1295 : /* "0","1","2","3","4" (1,3) -> "0","2","3","1","4" */
1296 15 : int i = 0; // Used after for.
1297 19 : for (; i < iOldFieldPos; i++)
1298 4 : panMap[i] = i;
1299 40 : for (; i < iNewFieldPos; i++)
1300 25 : panMap[i] = i + 1;
1301 15 : panMap[iNewFieldPos] = iOldFieldPos;
1302 27 : for (i = iNewFieldPos + 1; i < nFieldCount; i++)
1303 12 : panMap[i] = i;
1304 : }
1305 : else
1306 : {
1307 : /* "0","1","2","3","4" (3,1) -> "0","3","1","2","4" */
1308 23 : for (int i = 0; i < iNewFieldPos; i++)
1309 4 : panMap[i] = i;
1310 19 : panMap[iNewFieldPos] = iOldFieldPos;
1311 19 : int i = iNewFieldPos + 1; // Used after for.
1312 67 : for (; i <= iOldFieldPos; i++)
1313 48 : panMap[i] = i - 1;
1314 31 : for (; i < nFieldCount; i++)
1315 12 : panMap[i] = i;
1316 : }
1317 :
1318 34 : eErr = ReorderFields(panMap);
1319 :
1320 34 : CPLFree(panMap);
1321 :
1322 34 : return eErr;
1323 : }
1324 :
1325 : /************************************************************************/
1326 : /* OGR_L_ReorderField() */
1327 : /************************************************************************/
1328 :
1329 34 : OGRErr OGR_L_ReorderField(OGRLayerH hLayer, int iOldFieldPos, int iNewFieldPos)
1330 :
1331 : {
1332 34 : VALIDATE_POINTER1(hLayer, "OGR_L_ReorderField", OGRERR_INVALID_HANDLE);
1333 :
1334 : #ifdef OGRAPISPY_ENABLED
1335 34 : if (bOGRAPISpyEnabled)
1336 2 : OGRAPISpy_L_ReorderField(hLayer, iOldFieldPos, iNewFieldPos);
1337 : #endif
1338 :
1339 34 : return OGRLayer::FromHandle(hLayer)->ReorderField(iOldFieldPos,
1340 34 : iNewFieldPos);
1341 : }
1342 :
1343 : /************************************************************************/
1344 : /* AlterFieldDefn() */
1345 : /************************************************************************/
1346 :
1347 0 : OGRErr OGRLayer::AlterFieldDefn(int /* iField*/,
1348 : OGRFieldDefn * /*poNewFieldDefn*/,
1349 : int /* nFlags */)
1350 :
1351 : {
1352 0 : CPLError(CE_Failure, CPLE_NotSupported,
1353 : "AlterFieldDefn() not supported by this layer.\n");
1354 :
1355 0 : return OGRERR_UNSUPPORTED_OPERATION;
1356 : }
1357 :
1358 : /************************************************************************/
1359 : /* OGR_L_AlterFieldDefn() */
1360 : /************************************************************************/
1361 :
1362 126 : OGRErr OGR_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
1363 : OGRFieldDefnH hNewFieldDefn, int nFlags)
1364 :
1365 : {
1366 126 : VALIDATE_POINTER1(hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE);
1367 126 : VALIDATE_POINTER1(hNewFieldDefn, "OGR_L_AlterFieldDefn",
1368 : OGRERR_INVALID_HANDLE);
1369 :
1370 : #ifdef OGRAPISPY_ENABLED
1371 126 : if (bOGRAPISpyEnabled)
1372 2 : OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
1373 : #endif
1374 :
1375 252 : return OGRLayer::FromHandle(hLayer)->AlterFieldDefn(
1376 126 : iField, OGRFieldDefn::FromHandle(hNewFieldDefn), nFlags);
1377 : }
1378 :
1379 : /************************************************************************/
1380 : /* AlterGeomFieldDefn() */
1381 : /************************************************************************/
1382 :
1383 : OGRErr
1384 0 : OGRLayer::AlterGeomFieldDefn(int /* iGeomField*/,
1385 : const OGRGeomFieldDefn * /*poNewGeomFieldDefn*/,
1386 : int /* nFlags */)
1387 :
1388 : {
1389 0 : CPLError(CE_Failure, CPLE_NotSupported,
1390 : "AlterGeomFieldDefn() not supported by this layer.\n");
1391 :
1392 0 : return OGRERR_UNSUPPORTED_OPERATION;
1393 : }
1394 :
1395 : /************************************************************************/
1396 : /* OGR_L_AlterGeomFieldDefn() */
1397 : /************************************************************************/
1398 :
1399 33 : OGRErr OGR_L_AlterGeomFieldDefn(OGRLayerH hLayer, int iGeomField,
1400 : OGRGeomFieldDefnH hNewGeomFieldDefn, int nFlags)
1401 :
1402 : {
1403 33 : VALIDATE_POINTER1(hLayer, "OGR_L_AlterGeomFieldDefn",
1404 : OGRERR_INVALID_HANDLE);
1405 33 : VALIDATE_POINTER1(hNewGeomFieldDefn, "OGR_L_AlterGeomFieldDefn",
1406 : OGRERR_INVALID_HANDLE);
1407 :
1408 66 : return OGRLayer::FromHandle(hLayer)->AlterGeomFieldDefn(
1409 : iGeomField,
1410 : const_cast<const OGRGeomFieldDefn *>(
1411 33 : OGRGeomFieldDefn::FromHandle(hNewGeomFieldDefn)),
1412 33 : nFlags);
1413 : }
1414 :
1415 : /************************************************************************/
1416 : /* CreateGeomField() */
1417 : /************************************************************************/
1418 :
1419 0 : OGRErr OGRLayer::CreateGeomField(const OGRGeomFieldDefn *poField, int bApproxOK)
1420 :
1421 : {
1422 : (void)poField;
1423 : (void)bApproxOK;
1424 :
1425 0 : CPLError(CE_Failure, CPLE_NotSupported,
1426 : "CreateGeomField() not supported by this layer.\n");
1427 :
1428 0 : return OGRERR_UNSUPPORTED_OPERATION;
1429 : }
1430 :
1431 : /************************************************************************/
1432 : /* OGR_L_CreateGeomField() */
1433 : /************************************************************************/
1434 :
1435 120 : OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
1436 : int bApproxOK)
1437 :
1438 : {
1439 120 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1440 120 : VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1441 :
1442 : #ifdef OGRAPISPY_ENABLED
1443 120 : if (bOGRAPISpyEnabled)
1444 2 : OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
1445 : #endif
1446 :
1447 240 : return OGRLayer::FromHandle(hLayer)->CreateGeomField(
1448 120 : OGRGeomFieldDefn::FromHandle(hField), bApproxOK);
1449 : }
1450 :
1451 : /************************************************************************/
1452 : /* StartTransaction() */
1453 : /************************************************************************/
1454 :
1455 656 : OGRErr OGRLayer::StartTransaction()
1456 :
1457 : {
1458 656 : return OGRERR_NONE;
1459 : }
1460 :
1461 : /************************************************************************/
1462 : /* OGR_L_StartTransaction() */
1463 : /************************************************************************/
1464 :
1465 158 : OGRErr OGR_L_StartTransaction(OGRLayerH hLayer)
1466 :
1467 : {
1468 158 : VALIDATE_POINTER1(hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE);
1469 :
1470 : #ifdef OGRAPISPY_ENABLED
1471 158 : if (bOGRAPISpyEnabled)
1472 2 : OGRAPISpy_L_StartTransaction(hLayer);
1473 : #endif
1474 :
1475 158 : return OGRLayer::FromHandle(hLayer)->StartTransaction();
1476 : }
1477 :
1478 : /************************************************************************/
1479 : /* CommitTransaction() */
1480 : /************************************************************************/
1481 :
1482 612 : OGRErr OGRLayer::CommitTransaction()
1483 :
1484 : {
1485 612 : return OGRERR_NONE;
1486 : }
1487 :
1488 : /************************************************************************/
1489 : /* OGR_L_CommitTransaction() */
1490 : /************************************************************************/
1491 :
1492 138 : OGRErr OGR_L_CommitTransaction(OGRLayerH hLayer)
1493 :
1494 : {
1495 138 : VALIDATE_POINTER1(hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE);
1496 :
1497 : #ifdef OGRAPISPY_ENABLED
1498 138 : if (bOGRAPISpyEnabled)
1499 2 : OGRAPISpy_L_CommitTransaction(hLayer);
1500 : #endif
1501 :
1502 138 : return OGRLayer::FromHandle(hLayer)->CommitTransaction();
1503 : }
1504 :
1505 : /************************************************************************/
1506 : /* RollbackTransaction() */
1507 : /************************************************************************/
1508 :
1509 47 : OGRErr OGRLayer::RollbackTransaction()
1510 :
1511 : {
1512 47 : return OGRERR_UNSUPPORTED_OPERATION;
1513 : }
1514 :
1515 : /************************************************************************/
1516 : /* OGR_L_RollbackTransaction() */
1517 : /************************************************************************/
1518 :
1519 26 : OGRErr OGR_L_RollbackTransaction(OGRLayerH hLayer)
1520 :
1521 : {
1522 26 : VALIDATE_POINTER1(hLayer, "OGR_L_RollbackTransaction",
1523 : OGRERR_INVALID_HANDLE);
1524 :
1525 : #ifdef OGRAPISPY_ENABLED
1526 26 : if (bOGRAPISpyEnabled)
1527 2 : OGRAPISpy_L_RollbackTransaction(hLayer);
1528 : #endif
1529 :
1530 26 : return OGRLayer::FromHandle(hLayer)->RollbackTransaction();
1531 : }
1532 :
1533 : /************************************************************************/
1534 : /* OGR_L_GetLayerDefn() */
1535 : /************************************************************************/
1536 :
1537 131313 : OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
1538 :
1539 : {
1540 131313 : VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
1541 :
1542 : #ifdef OGRAPISPY_ENABLED
1543 131313 : if (bOGRAPISpyEnabled)
1544 15 : OGRAPISpy_L_GetLayerDefn(hLayer);
1545 : #endif
1546 :
1547 131313 : return OGRFeatureDefn::ToHandle(
1548 262626 : OGRLayer::FromHandle(hLayer)->GetLayerDefn());
1549 : }
1550 :
1551 : /************************************************************************/
1552 : /* OGR_L_FindFieldIndex() */
1553 : /************************************************************************/
1554 :
1555 2 : int OGR_L_FindFieldIndex(OGRLayerH hLayer, const char *pszFieldName,
1556 : int bExactMatch)
1557 :
1558 : {
1559 2 : VALIDATE_POINTER1(hLayer, "OGR_L_FindFieldIndex", -1);
1560 :
1561 : #ifdef OGRAPISPY_ENABLED
1562 2 : if (bOGRAPISpyEnabled)
1563 2 : OGRAPISpy_L_FindFieldIndex(hLayer, pszFieldName, bExactMatch);
1564 : #endif
1565 :
1566 4 : return OGRLayer::FromHandle(hLayer)->FindFieldIndex(pszFieldName,
1567 2 : bExactMatch);
1568 : }
1569 :
1570 : /************************************************************************/
1571 : /* FindFieldIndex() */
1572 : /************************************************************************/
1573 :
1574 78 : int OGRLayer::FindFieldIndex(const char *pszFieldName,
1575 : CPL_UNUSED int bExactMatch)
1576 : {
1577 78 : return GetLayerDefn()->GetFieldIndex(pszFieldName);
1578 : }
1579 :
1580 : /************************************************************************/
1581 : /* GetSpatialRef() */
1582 : /************************************************************************/
1583 :
1584 425236 : OGRSpatialReference *OGRLayer::GetSpatialRef()
1585 : {
1586 425236 : if (GetLayerDefn()->GetGeomFieldCount() > 0)
1587 : return const_cast<OGRSpatialReference *>(
1588 424776 : GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef());
1589 : else
1590 460 : return nullptr;
1591 : }
1592 :
1593 : /************************************************************************/
1594 : /* OGR_L_GetSpatialRef() */
1595 : /************************************************************************/
1596 :
1597 1029 : OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
1598 :
1599 : {
1600 1029 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
1601 :
1602 : #ifdef OGRAPISPY_ENABLED
1603 1029 : if (bOGRAPISpyEnabled)
1604 2 : OGRAPISpy_L_GetSpatialRef(hLayer);
1605 : #endif
1606 :
1607 1029 : return OGRSpatialReference::ToHandle(
1608 2058 : OGRLayer::FromHandle(hLayer)->GetSpatialRef());
1609 : }
1610 :
1611 : /************************************************************************/
1612 : /* OGR_L_TestCapability() */
1613 : /************************************************************************/
1614 :
1615 825 : int OGR_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
1616 :
1617 : {
1618 825 : VALIDATE_POINTER1(hLayer, "OGR_L_TestCapability", 0);
1619 825 : VALIDATE_POINTER1(pszCap, "OGR_L_TestCapability", 0);
1620 :
1621 : #ifdef OGRAPISPY_ENABLED
1622 825 : if (bOGRAPISpyEnabled)
1623 2 : OGRAPISpy_L_TestCapability(hLayer, pszCap);
1624 : #endif
1625 :
1626 825 : return OGRLayer::FromHandle(hLayer)->TestCapability(pszCap);
1627 : }
1628 :
1629 : /************************************************************************/
1630 : /* GetSpatialFilter() */
1631 : /************************************************************************/
1632 :
1633 389 : OGRGeometry *OGRLayer::GetSpatialFilter()
1634 :
1635 : {
1636 389 : return m_poFilterGeom;
1637 : }
1638 :
1639 : /************************************************************************/
1640 : /* OGR_L_GetSpatialFilter() */
1641 : /************************************************************************/
1642 :
1643 5 : OGRGeometryH OGR_L_GetSpatialFilter(OGRLayerH hLayer)
1644 :
1645 : {
1646 5 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialFilter", nullptr);
1647 :
1648 : #ifdef OGRAPISPY_ENABLED
1649 5 : if (bOGRAPISpyEnabled)
1650 2 : OGRAPISpy_L_GetSpatialFilter(hLayer);
1651 : #endif
1652 :
1653 5 : return OGRGeometry::ToHandle(
1654 10 : OGRLayer::FromHandle(hLayer)->GetSpatialFilter());
1655 : }
1656 :
1657 : /************************************************************************/
1658 : /* ValidateGeometryFieldIndexForSetSpatialFilter() */
1659 : /************************************************************************/
1660 :
1661 : //! @cond Doxygen_Suppress
1662 53268 : bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
1663 : int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
1664 : {
1665 53268 : if (iGeomField == 0 && poGeomIn == nullptr &&
1666 0 : GetLayerDefn()->GetGeomFieldCount() == 0)
1667 : {
1668 : // Setting a null spatial filter on geometry field idx 0
1669 : // when there are no geometry field can't harm, and is accepted silently
1670 : // for backward compatibility with existing practice.
1671 : }
1672 106296 : else if (iGeomField < 0 ||
1673 53028 : iGeomField >= GetLayerDefn()->GetGeomFieldCount())
1674 : {
1675 561 : if (iGeomField == 0)
1676 : {
1677 79 : CPLError(
1678 : CE_Failure, CPLE_AppDefined,
1679 : bIsSelectLayer
1680 : ? "Cannot set spatial filter: no geometry field selected."
1681 : : "Cannot set spatial filter: no geometry field present in "
1682 : "layer.");
1683 : }
1684 : else
1685 : {
1686 482 : CPLError(CE_Failure, CPLE_AppDefined,
1687 : "Cannot set spatial filter on non-existing geometry field "
1688 : "of index %d.",
1689 : iGeomField);
1690 : }
1691 561 : return false;
1692 : }
1693 52707 : return true;
1694 : }
1695 :
1696 : //! @endcond
1697 :
1698 : /************************************************************************/
1699 : /* SetSpatialFilter() */
1700 : /************************************************************************/
1701 :
1702 : /**
1703 : \brief Set a new spatial filter.
1704 :
1705 : This method set the geometry to be used as a spatial filter when
1706 : fetching features via the GetNextFeature() method. Only features that
1707 : geometrically intersect the filter geometry will be returned.
1708 :
1709 : Currently this test is may be inaccurately implemented, but it is
1710 : guaranteed that all features whose envelope (as returned by
1711 : OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
1712 : will be returned. This can result in more shapes being returned that
1713 : should strictly be the case.
1714 :
1715 : Starting with GDAL 2.3, features with null or empty geometries will never
1716 : be considered as matching a spatial filter.
1717 :
1718 : This method makes an internal copy of the passed geometry. The
1719 : passed geometry remains the responsibility of the caller, and may
1720 : be safely destroyed.
1721 :
1722 : For the time being the passed filter geometry should be in the same
1723 : SRS as the layer (as returned by OGRLayer::GetSpatialRef()). In the
1724 : future this may be generalized.
1725 :
1726 : This method is the same as the C function OGR_L_SetSpatialFilter().
1727 :
1728 : @param poFilter the geometry to use as a filtering region. NULL may
1729 : be passed indicating that the current spatial filter should be cleared,
1730 : but no new one instituted.
1731 : */
1732 :
1733 6660 : OGRErr OGRLayer::SetSpatialFilter(const OGRGeometry *poFilter)
1734 :
1735 : {
1736 6660 : return SetSpatialFilter(0, poFilter);
1737 : }
1738 :
1739 : /**
1740 : \brief Set a new spatial filter.
1741 :
1742 : This method set the geometry to be used as a spatial filter when
1743 : fetching features via the GetNextFeature() method. Only features that
1744 : geometrically intersect the filter geometry will be returned.
1745 :
1746 : Currently this test is may be inaccurately implemented, but it is
1747 : guaranteed that all features who's envelope (as returned by
1748 : OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
1749 : will be returned. This can result in more shapes being returned that
1750 : should strictly be the case.
1751 :
1752 : This method makes an internal copy of the passed geometry. The
1753 : passed geometry remains the responsibility of the caller, and may
1754 : be safely destroyed.
1755 :
1756 : For the time being the passed filter geometry should be in the same
1757 : SRS as the geometry field definition it corresponds to (as returned by
1758 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). In the
1759 : future this may be generalized.
1760 :
1761 : Note that only the last spatial filter set is applied, even if several
1762 : successive calls are done with different iGeomField values.
1763 :
1764 : This method is the same as the C function OGR_L_SetSpatialFilterEx().
1765 :
1766 : @param iGeomField index of the geometry field on which the spatial filter
1767 : operates.
1768 : @param poFilter the geometry to use as a filtering region. NULL may
1769 : be passed indicating that the current spatial filter should be cleared,
1770 : but no new one instituted.
1771 :
1772 : @since GDAL 1.11
1773 : */
1774 :
1775 65567 : OGRErr OGRLayer::SetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
1776 :
1777 : {
1778 65567 : if (iGeomField == 0)
1779 : {
1780 115887 : if (poFilter &&
1781 51793 : !ValidateGeometryFieldIndexForSetSpatialFilter(0, poFilter))
1782 : {
1783 79 : return OGRERR_FAILURE;
1784 : }
1785 : }
1786 : else
1787 : {
1788 1473 : if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField,
1789 : poFilter))
1790 : {
1791 482 : return OGRERR_FAILURE;
1792 : }
1793 : }
1794 :
1795 65006 : return ISetSpatialFilter(iGeomField, poFilter);
1796 : }
1797 :
1798 : /************************************************************************/
1799 : /* ISetSpatialFilter() */
1800 : /************************************************************************/
1801 :
1802 : /**
1803 : \brief Set a new spatial filter.
1804 :
1805 : Virtual method implemented by drivers since 3.11. In previous versions,
1806 : SetSpatialFilter() / SetSpatialFilterRect() itself was the virtual method.
1807 :
1808 : Driver implementations, when wanting to call the base method, must take
1809 : care of calling OGRLayer::ISetSpatialFilter() (and note the public method without
1810 : the leading I).
1811 :
1812 : @param iGeomField index of the geometry field on which the spatial filter
1813 : operates.
1814 : @param poFilter the geometry to use as a filtering region. NULL may
1815 : be passed indicating that the current spatial filter should be cleared,
1816 : but no new one instituted.
1817 :
1818 : @since GDAL 3.11
1819 : */
1820 :
1821 36488 : OGRErr OGRLayer::ISetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
1822 :
1823 : {
1824 36488 : m_iGeomFieldFilter = iGeomField;
1825 36488 : if (InstallFilter(poFilter))
1826 28430 : ResetReading();
1827 36488 : return OGRERR_NONE;
1828 : }
1829 :
1830 : /************************************************************************/
1831 : /* OGR_L_SetSpatialFilter() */
1832 : /************************************************************************/
1833 :
1834 : /**
1835 : \brief Set a new spatial filter.
1836 :
1837 : This function set the geometry to be used as a spatial filter when
1838 : fetching features via the OGR_L_GetNextFeature() function. Only
1839 : features that geometrically intersect the filter geometry will be
1840 : returned.
1841 :
1842 : Currently this test is may be inaccurately implemented, but it is
1843 : guaranteed that all features whose envelope (as returned by
1844 : OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
1845 : will be returned. This can result in more shapes being returned that
1846 : should strictly be the case.
1847 :
1848 : Starting with GDAL 2.3, features with null or empty geometries will never
1849 : be considered as matching a spatial filter.
1850 :
1851 : This function makes an internal copy of the passed geometry. The
1852 : passed geometry remains the responsibility of the caller, and may
1853 : be safely destroyed.
1854 :
1855 : For the time being the passed filter geometry should be in the same
1856 : SRS as the layer (as returned by OGR_L_GetSpatialRef()). In the
1857 : future this may be generalized.
1858 :
1859 : This function is the same as the C++ method OGRLayer::SetSpatialFilter.
1860 :
1861 : @param hLayer handle to the layer on which to set the spatial filter.
1862 : @param hGeom handle to the geometry to use as a filtering region. NULL may
1863 : be passed indicating that the current spatial filter should be cleared,
1864 : but no new one instituted.
1865 :
1866 : */
1867 :
1868 648 : void OGR_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
1869 :
1870 : {
1871 648 : VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilter");
1872 :
1873 : #ifdef OGRAPISPY_ENABLED
1874 648 : if (bOGRAPISpyEnabled)
1875 4 : OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
1876 : #endif
1877 :
1878 1296 : OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
1879 648 : OGRGeometry::FromHandle(hGeom));
1880 : }
1881 :
1882 : /************************************************************************/
1883 : /* OGR_L_SetSpatialFilterEx() */
1884 : /************************************************************************/
1885 :
1886 : /**
1887 : \brief Set a new spatial filter.
1888 :
1889 : This function set the geometry to be used as a spatial filter when
1890 : fetching features via the OGR_L_GetNextFeature() function. Only
1891 : features that geometrically intersect the filter geometry will be
1892 : returned.
1893 :
1894 : Currently this test is may be inaccurately implemented, but it is
1895 : guaranteed that all features who's envelope (as returned by
1896 : OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
1897 : will be returned. This can result in more shapes being returned that
1898 : should strictly be the case.
1899 :
1900 : This function makes an internal copy of the passed geometry. The
1901 : passed geometry remains the responsibility of the caller, and may
1902 : be safely destroyed.
1903 :
1904 : For the time being the passed filter geometry should be in the same
1905 : SRS as the geometry field definition it corresponds to (as returned by
1906 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). In the
1907 : future this may be generalized.
1908 :
1909 : Note that only the last spatial filter set is applied, even if several
1910 : successive calls are done with different iGeomField values.
1911 :
1912 : This function is the same as the C++ method OGRLayer::SetSpatialFilter.
1913 :
1914 : @param hLayer handle to the layer on which to set the spatial filter.
1915 : @param iGeomField index of the geometry field on which the spatial filter
1916 : operates.
1917 : @param hGeom handle to the geometry to use as a filtering region. NULL may
1918 : be passed indicating that the current spatial filter should be cleared,
1919 : but no new one instituted.
1920 :
1921 : @since GDAL 1.11
1922 :
1923 : */
1924 :
1925 12 : void OGR_L_SetSpatialFilterEx(OGRLayerH hLayer, int iGeomField,
1926 : OGRGeometryH hGeom)
1927 :
1928 : {
1929 12 : VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterEx");
1930 :
1931 : #ifdef OGRAPISPY_ENABLED
1932 12 : if (bOGRAPISpyEnabled)
1933 2 : OGRAPISpy_L_SetSpatialFilterEx(hLayer, iGeomField, hGeom);
1934 : #endif
1935 :
1936 24 : OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
1937 12 : iGeomField, OGRGeometry::FromHandle(hGeom));
1938 : }
1939 :
1940 : /************************************************************************/
1941 : /* SetSpatialFilterRect() */
1942 : /************************************************************************/
1943 :
1944 : /**
1945 : \brief Set a new rectangular spatial filter.
1946 :
1947 : This method set rectangle to be used as a spatial filter when
1948 : fetching features via the GetNextFeature() method. Only features that
1949 : geometrically intersect the given rectangle will be returned.
1950 :
1951 : The x/y values should be in the same coordinate system as the layer as
1952 : a whole (as returned by OGRLayer::GetSpatialRef()). Internally this
1953 : method is normally implemented as creating a 5 vertex closed rectangular
1954 : polygon and passing it to OGRLayer::SetSpatialFilter(). It exists as
1955 : a convenience.
1956 :
1957 : The only way to clear a spatial filter set with this method is to
1958 : call OGRLayer::SetSpatialFilter(NULL).
1959 :
1960 : This method is the same as the C function OGR_L_SetSpatialFilterRect().
1961 :
1962 : @param dfMinX the minimum X coordinate for the rectangular region.
1963 : @param dfMinY the minimum Y coordinate for the rectangular region.
1964 : @param dfMaxX the maximum X coordinate for the rectangular region.
1965 : @param dfMaxY the maximum Y coordinate for the rectangular region.
1966 :
1967 : */
1968 :
1969 48040 : OGRErr OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY,
1970 : double dfMaxX, double dfMaxY)
1971 :
1972 : {
1973 48040 : return SetSpatialFilterRect(0, dfMinX, dfMinY, dfMaxX, dfMaxY);
1974 : }
1975 :
1976 : /**
1977 : \brief Set a new rectangular spatial filter.
1978 :
1979 : This method set rectangle to be used as a spatial filter when
1980 : fetching features via the GetNextFeature() method. Only features that
1981 : geometrically intersect the given rectangle will be returned.
1982 :
1983 : The x/y values should be in the same coordinate system as as the geometry
1984 : field definition it corresponds to (as returned by
1985 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
1986 : method is normally implemented as creating a 5 vertex closed rectangular
1987 : polygon and passing it to OGRLayer::SetSpatialFilter(). It exists as
1988 : a convenience.
1989 :
1990 : The only way to clear a spatial filter set with this method is to
1991 : call OGRLayer::SetSpatialFilter(NULL).
1992 :
1993 : This method is the same as the C function OGR_L_SetSpatialFilterRectEx().
1994 :
1995 : @param iGeomField index of the geometry field on which the spatial filter
1996 : operates.
1997 : @param dfMinX the minimum X coordinate for the rectangular region.
1998 : @param dfMinY the minimum Y coordinate for the rectangular region.
1999 : @param dfMaxX the maximum X coordinate for the rectangular region.
2000 : @param dfMaxY the maximum Y coordinate for the rectangular region.
2001 :
2002 : @since GDAL 1.11
2003 : */
2004 :
2005 48094 : OGRErr OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
2006 : double dfMinY, double dfMaxX,
2007 : double dfMaxY)
2008 :
2009 : {
2010 96188 : auto poRing = std::make_unique<OGRLinearRing>();
2011 96188 : OGRPolygon oPoly;
2012 :
2013 48094 : poRing->addPoint(dfMinX, dfMinY);
2014 48094 : poRing->addPoint(dfMinX, dfMaxY);
2015 48094 : poRing->addPoint(dfMaxX, dfMaxY);
2016 48094 : poRing->addPoint(dfMaxX, dfMinY);
2017 48094 : poRing->addPoint(dfMinX, dfMinY);
2018 :
2019 48094 : oPoly.addRing(std::move(poRing));
2020 :
2021 96188 : return SetSpatialFilter(iGeomField, &oPoly);
2022 : }
2023 :
2024 : /************************************************************************/
2025 : /* OGR_L_SetSpatialFilterRect() */
2026 : /************************************************************************/
2027 :
2028 : /**
2029 : \brief Set a new rectangular spatial filter.
2030 :
2031 : This method set rectangle to be used as a spatial filter when
2032 : fetching features via the OGR_L_GetNextFeature() method. Only features that
2033 : geometrically intersect the given rectangle will be returned.
2034 :
2035 : The x/y values should be in the same coordinate system as the layer as
2036 : a whole (as returned by OGRLayer::GetSpatialRef()). Internally this
2037 : method is normally implemented as creating a 5 vertex closed rectangular
2038 : polygon and passing it to OGRLayer::SetSpatialFilter(). It exists as
2039 : a convenience.
2040 :
2041 : The only way to clear a spatial filter set with this method is to
2042 : call OGRLayer::SetSpatialFilter(NULL).
2043 :
2044 : This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
2045 :
2046 : @param hLayer handle to the layer on which to set the spatial filter.
2047 : @param dfMinX the minimum X coordinate for the rectangular region.
2048 : @param dfMinY the minimum Y coordinate for the rectangular region.
2049 : @param dfMaxX the maximum X coordinate for the rectangular region.
2050 : @param dfMaxY the maximum Y coordinate for the rectangular region.
2051 :
2052 : */
2053 :
2054 47752 : void OGR_L_SetSpatialFilterRect(OGRLayerH hLayer, double dfMinX, double dfMinY,
2055 : double dfMaxX, double dfMaxY)
2056 :
2057 : {
2058 47752 : VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRect");
2059 :
2060 : #ifdef OGRAPISPY_ENABLED
2061 47752 : if (bOGRAPISpyEnabled)
2062 2 : OGRAPISpy_L_SetSpatialFilterRect(hLayer, dfMinX, dfMinY, dfMaxX,
2063 : dfMaxY);
2064 : #endif
2065 :
2066 47752 : OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX,
2067 : dfMaxY);
2068 : }
2069 :
2070 : /************************************************************************/
2071 : /* OGR_L_SetSpatialFilterRectEx() */
2072 : /************************************************************************/
2073 :
2074 : /**
2075 : \brief Set a new rectangular spatial filter.
2076 :
2077 : This method set rectangle to be used as a spatial filter when
2078 : fetching features via the OGR_L_GetNextFeature() method. Only features that
2079 : geometrically intersect the given rectangle will be returned.
2080 :
2081 : The x/y values should be in the same coordinate system as as the geometry
2082 : field definition it corresponds to (as returned by
2083 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
2084 : method is normally implemented as creating a 5 vertex closed rectangular
2085 : polygon and passing it to OGRLayer::SetSpatialFilter(). It exists as
2086 : a convenience.
2087 :
2088 : The only way to clear a spatial filter set with this method is to
2089 : call OGRLayer::SetSpatialFilter(NULL).
2090 :
2091 : This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
2092 :
2093 : @param hLayer handle to the layer on which to set the spatial filter.
2094 : @param iGeomField index of the geometry field on which the spatial filter
2095 : operates.
2096 : @param dfMinX the minimum X coordinate for the rectangular region.
2097 : @param dfMinY the minimum Y coordinate for the rectangular region.
2098 : @param dfMaxX the maximum X coordinate for the rectangular region.
2099 : @param dfMaxY the maximum Y coordinate for the rectangular region.
2100 :
2101 : @since GDAL 1.11
2102 : */
2103 :
2104 15 : void OGR_L_SetSpatialFilterRectEx(OGRLayerH hLayer, int iGeomField,
2105 : double dfMinX, double dfMinY, double dfMaxX,
2106 : double dfMaxY)
2107 :
2108 : {
2109 15 : VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRectEx");
2110 :
2111 : #ifdef OGRAPISPY_ENABLED
2112 15 : if (bOGRAPISpyEnabled)
2113 2 : OGRAPISpy_L_SetSpatialFilterRectEx(hLayer, iGeomField, dfMinX, dfMinY,
2114 : dfMaxX, dfMaxY);
2115 : #endif
2116 :
2117 15 : OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(iGeomField, dfMinX,
2118 : dfMinY, dfMaxX, dfMaxY);
2119 : }
2120 :
2121 : /************************************************************************/
2122 : /* InstallFilter() */
2123 : /* */
2124 : /* This method is only intended to be used from within */
2125 : /* drivers, normally from the SetSpatialFilter() method. */
2126 : /* It installs a filter, and also tests it to see if it is */
2127 : /* rectangular. If so, it this is kept track of alongside the */
2128 : /* filter geometry itself so we can do cheaper comparisons in */
2129 : /* the FilterGeometry() call. */
2130 : /* */
2131 : /* Returns TRUE if the newly installed filter differs in some */
2132 : /* way from the current one. */
2133 : /************************************************************************/
2134 :
2135 : //! @cond Doxygen_Suppress
2136 64152 : int OGRLayer::InstallFilter(const OGRGeometry *poFilter)
2137 :
2138 : {
2139 64152 : if (m_poFilterGeom == poFilter)
2140 10221 : return FALSE;
2141 :
2142 : /* -------------------------------------------------------------------- */
2143 : /* Replace the existing filter. */
2144 : /* -------------------------------------------------------------------- */
2145 53931 : if (m_poFilterGeom != nullptr)
2146 : {
2147 51065 : delete m_poFilterGeom;
2148 51065 : m_poFilterGeom = nullptr;
2149 : }
2150 :
2151 53931 : if (m_pPreparedFilterGeom != nullptr)
2152 : {
2153 51065 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
2154 51065 : m_pPreparedFilterGeom = nullptr;
2155 : }
2156 :
2157 53931 : if (poFilter != nullptr)
2158 51929 : m_poFilterGeom = poFilter->clone();
2159 :
2160 53931 : m_bFilterIsEnvelope = FALSE;
2161 :
2162 53931 : if (m_poFilterGeom == nullptr)
2163 2002 : return TRUE;
2164 :
2165 51929 : m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
2166 :
2167 : /* Compile geometry filter as a prepared geometry */
2168 51929 : m_pPreparedFilterGeom =
2169 51929 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
2170 :
2171 51929 : m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
2172 :
2173 51929 : return TRUE;
2174 : }
2175 :
2176 : //! @endcond
2177 :
2178 : /************************************************************************/
2179 : /* DoesGeometryHavePointInEnvelope() */
2180 : /************************************************************************/
2181 :
2182 5215 : static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
2183 : const OGREnvelope &sEnvelope)
2184 : {
2185 5215 : const OGRLineString *poLS = nullptr;
2186 :
2187 5215 : switch (wkbFlatten(poGeometry->getGeometryType()))
2188 : {
2189 36 : case wkbPoint:
2190 : {
2191 36 : const auto poPoint = poGeometry->toPoint();
2192 36 : const double x = poPoint->getX();
2193 36 : const double y = poPoint->getY();
2194 31 : return (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
2195 67 : x <= sEnvelope.MaxX && y <= sEnvelope.MaxY);
2196 : }
2197 :
2198 394 : case wkbLineString:
2199 394 : poLS = poGeometry->toLineString();
2200 394 : break;
2201 :
2202 4083 : case wkbPolygon:
2203 : {
2204 4083 : const OGRPolygon *poPoly = poGeometry->toPolygon();
2205 4083 : poLS = poPoly->getExteriorRing();
2206 4083 : break;
2207 : }
2208 :
2209 461 : case wkbMultiPoint:
2210 : case wkbMultiLineString:
2211 : case wkbMultiPolygon:
2212 : case wkbGeometryCollection:
2213 : {
2214 693 : for (const auto &poSubGeom : *(poGeometry->toGeometryCollection()))
2215 : {
2216 607 : if (DoesGeometryHavePointInEnvelope(poSubGeom, sEnvelope))
2217 375 : return true;
2218 : }
2219 86 : return false;
2220 : }
2221 :
2222 241 : default:
2223 241 : return false;
2224 : }
2225 :
2226 4477 : if (poLS != nullptr)
2227 : {
2228 4477 : const int nNumPoints = poLS->getNumPoints();
2229 52142 : for (int i = 0; i < nNumPoints; i++)
2230 : {
2231 51129 : const double x = poLS->getX(i);
2232 51129 : const double y = poLS->getY(i);
2233 51129 : if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
2234 20319 : x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
2235 : {
2236 3464 : return true;
2237 : }
2238 : }
2239 : }
2240 :
2241 1013 : return false;
2242 : }
2243 :
2244 : /************************************************************************/
2245 : /* FilterGeometry() */
2246 : /* */
2247 : /* Compare the passed in geometry to the currently installed */
2248 : /* filter. Optimize for case where filter is just an */
2249 : /* envelope. */
2250 : /************************************************************************/
2251 :
2252 : //! @cond Doxygen_Suppress
2253 454049 : int OGRLayer::FilterGeometry(const OGRGeometry *poGeometry)
2254 :
2255 : {
2256 : /* -------------------------------------------------------------------- */
2257 : /* In trivial cases of new filter or target geometry, we accept */
2258 : /* an intersection. No geometry is taken to mean "the whole */
2259 : /* world". */
2260 : /* -------------------------------------------------------------------- */
2261 454049 : if (m_poFilterGeom == nullptr)
2262 376 : return TRUE;
2263 :
2264 453673 : if (poGeometry == nullptr || poGeometry->IsEmpty())
2265 303 : return FALSE;
2266 :
2267 : /* -------------------------------------------------------------------- */
2268 : /* Compute the target geometry envelope, and if there is no */
2269 : /* intersection between the envelopes we are sure not to have */
2270 : /* any intersection. */
2271 : /* -------------------------------------------------------------------- */
2272 453370 : OGREnvelope sGeomEnv;
2273 :
2274 453370 : poGeometry->getEnvelope(&sGeomEnv);
2275 :
2276 453370 : if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
2277 299596 : sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
2278 231273 : m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
2279 130621 : m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
2280 339165 : return FALSE;
2281 :
2282 : /* -------------------------------------------------------------------- */
2283 : /* If the filter geometry is its own envelope and if the */
2284 : /* envelope of the geometry is inside the filter geometry, */
2285 : /* the geometry itself is inside the filter geometry */
2286 : /* -------------------------------------------------------------------- */
2287 114205 : if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
2288 110949 : sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
2289 109722 : sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
2290 108902 : sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
2291 : {
2292 108515 : return TRUE;
2293 : }
2294 : else
2295 : {
2296 : // If the filter geometry is its own envelope and if the geometry has
2297 : // at least one point inside the filter geometry, the geometry itself
2298 : // intersects the filter geometry.
2299 5690 : if (m_bFilterIsEnvelope)
2300 : {
2301 4608 : if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
2302 3474 : return true;
2303 : }
2304 :
2305 : /* --------------------------------------------------------------------
2306 : */
2307 : /* Fallback to full intersect test (using GEOS) if we still */
2308 : /* don't know for sure. */
2309 : /* --------------------------------------------------------------------
2310 : */
2311 2216 : if (OGRGeometryFactory::haveGEOS())
2312 : {
2313 : // CPLDebug("OGRLayer", "GEOS intersection");
2314 2216 : if (m_pPreparedFilterGeom != nullptr)
2315 2216 : return OGRPreparedGeometryIntersects(
2316 : m_pPreparedFilterGeom,
2317 : OGRGeometry::ToHandle(
2318 2216 : const_cast<OGRGeometry *>(poGeometry)));
2319 : else
2320 0 : return m_poFilterGeom->Intersects(poGeometry);
2321 : }
2322 : else
2323 0 : return TRUE;
2324 : }
2325 : }
2326 :
2327 : /************************************************************************/
2328 : /* FilterWKBGeometry() */
2329 : /************************************************************************/
2330 :
2331 230 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
2332 : bool bEnvelopeAlreadySet,
2333 : OGREnvelope &sEnvelope) const
2334 : {
2335 230 : OGRPreparedGeometry *pPreparedFilterGeom = m_pPreparedFilterGeom;
2336 460 : bool bRet = FilterWKBGeometry(
2337 230 : pabyWKB, nWKBSize, bEnvelopeAlreadySet, sEnvelope, m_poFilterGeom,
2338 230 : m_bFilterIsEnvelope, m_sFilterEnvelope, pPreparedFilterGeom);
2339 230 : const_cast<OGRLayer *>(this)->m_pPreparedFilterGeom = pPreparedFilterGeom;
2340 230 : return bRet;
2341 : }
2342 :
2343 : /* static */
2344 334 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
2345 : bool bEnvelopeAlreadySet,
2346 : OGREnvelope &sEnvelope,
2347 : const OGRGeometry *poFilterGeom,
2348 : bool bFilterIsEnvelope,
2349 : const OGREnvelope &sFilterEnvelope,
2350 : OGRPreparedGeometry *&pPreparedFilterGeom)
2351 : {
2352 334 : if (!poFilterGeom)
2353 0 : return true;
2354 :
2355 637 : if ((bEnvelopeAlreadySet ||
2356 668 : OGRWKBGetBoundingBox(pabyWKB, nWKBSize, sEnvelope)) &&
2357 334 : sFilterEnvelope.Intersects(sEnvelope))
2358 : {
2359 161 : if (bFilterIsEnvelope && sFilterEnvelope.Contains(sEnvelope))
2360 : {
2361 98 : return true;
2362 : }
2363 : else
2364 : {
2365 126 : if (bFilterIsEnvelope &&
2366 63 : OGRWKBIntersectsPessimistic(pabyWKB, nWKBSize, sFilterEnvelope))
2367 : {
2368 51 : return true;
2369 : }
2370 12 : else if (OGRGeometryFactory::haveGEOS())
2371 : {
2372 12 : OGRGeometry *poGeom = nullptr;
2373 12 : int ret = FALSE;
2374 12 : if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeom,
2375 12 : nWKBSize) == OGRERR_NONE)
2376 : {
2377 12 : if (!pPreparedFilterGeom)
2378 : {
2379 0 : pPreparedFilterGeom =
2380 0 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(
2381 : const_cast<OGRGeometry *>(poFilterGeom)));
2382 : }
2383 12 : if (pPreparedFilterGeom)
2384 12 : ret = OGRPreparedGeometryIntersects(
2385 : pPreparedFilterGeom,
2386 : OGRGeometry::ToHandle(
2387 : const_cast<OGRGeometry *>(poGeom)));
2388 : else
2389 0 : ret = poFilterGeom->Intersects(poGeom);
2390 : }
2391 12 : delete poGeom;
2392 12 : return CPL_TO_BOOL(ret);
2393 : }
2394 : else
2395 : {
2396 : // Assume intersection
2397 0 : return true;
2398 : }
2399 : }
2400 : }
2401 :
2402 173 : return false;
2403 : }
2404 :
2405 : /************************************************************************/
2406 : /* PrepareStartTransaction() */
2407 : /************************************************************************/
2408 :
2409 3330 : void OGRLayer::PrepareStartTransaction()
2410 : {
2411 3330 : m_apoFieldDefnChanges.clear();
2412 3330 : m_apoGeomFieldDefnChanges.clear();
2413 3330 : }
2414 :
2415 : /************************************************************************/
2416 : /* FinishRollbackTransaction() */
2417 : /************************************************************************/
2418 :
2419 171 : void OGRLayer::FinishRollbackTransaction(const std::string &osSavepointName)
2420 : {
2421 :
2422 : // Deleted fields can be safely removed from the storage after being restored.
2423 342 : std::vector<int> toBeRemoved;
2424 :
2425 171 : bool bSavepointFound = false;
2426 :
2427 : // Loop through all changed fields and reset them to their previous state.
2428 374 : for (int i = static_cast<int>(m_apoFieldDefnChanges.size()) - 1; i >= 0;
2429 : i--)
2430 : {
2431 203 : auto &oFieldChange = m_apoFieldDefnChanges[i];
2432 :
2433 203 : if (!osSavepointName.empty())
2434 : {
2435 172 : if (oFieldChange.osSavepointName == osSavepointName)
2436 : {
2437 60 : bSavepointFound = true;
2438 : }
2439 112 : else if (bSavepointFound)
2440 : {
2441 56 : continue;
2442 : }
2443 : }
2444 :
2445 147 : CPLAssert(oFieldChange.poFieldDefn);
2446 147 : const char *pszName = oFieldChange.poFieldDefn->GetNameRef();
2447 147 : const int iField = oFieldChange.iField;
2448 147 : if (iField >= 0)
2449 : {
2450 147 : switch (oFieldChange.eChangeType)
2451 : {
2452 128 : case FieldChangeType::DELETE_FIELD:
2453 : {
2454 : // Transfer ownership of the field to the layer
2455 256 : whileUnsealing(GetLayerDefn())
2456 128 : ->AddFieldDefn(std::move(oFieldChange.poFieldDefn));
2457 :
2458 : // Now move the field to the right place
2459 : // from the last position to its original position
2460 128 : const int iFieldCount = GetLayerDefn()->GetFieldCount();
2461 128 : CPLAssert(iFieldCount > 0);
2462 128 : CPLAssert(iFieldCount > iField);
2463 256 : std::vector<int> anOrder(iFieldCount);
2464 204 : for (int j = 0; j < iField; j++)
2465 : {
2466 76 : anOrder[j] = j;
2467 : }
2468 248 : for (int j = iField + 1; j < iFieldCount; j++)
2469 : {
2470 120 : anOrder[j] = j - 1;
2471 : }
2472 128 : anOrder[iField] = iFieldCount - 1;
2473 256 : if (OGRERR_NONE == whileUnsealing(GetLayerDefn())
2474 128 : ->ReorderFieldDefns(anOrder.data()))
2475 : {
2476 128 : toBeRemoved.push_back(i);
2477 : }
2478 : else
2479 : {
2480 0 : CPLError(CE_Failure, CPLE_AppDefined,
2481 : "Failed to restore deleted field %s", pszName);
2482 : }
2483 128 : break;
2484 : }
2485 8 : case FieldChangeType::ALTER_FIELD:
2486 : {
2487 : OGRFieldDefn *poFieldDefn =
2488 8 : GetLayerDefn()->GetFieldDefn(iField);
2489 8 : if (poFieldDefn)
2490 : {
2491 8 : *poFieldDefn = *oFieldChange.poFieldDefn;
2492 8 : toBeRemoved.push_back(i);
2493 : }
2494 : else
2495 : {
2496 0 : CPLError(CE_Failure, CPLE_AppDefined,
2497 : "Failed to restore altered field %s", pszName);
2498 : }
2499 8 : break;
2500 : }
2501 11 : case FieldChangeType::ADD_FIELD:
2502 : {
2503 : std::unique_ptr<OGRFieldDefn> poFieldDef =
2504 22 : GetLayerDefn()->StealFieldDefn(iField);
2505 11 : if (poFieldDef)
2506 : {
2507 11 : oFieldChange.poFieldDefn = std::move(poFieldDef);
2508 : }
2509 : else
2510 : {
2511 0 : CPLError(CE_Failure, CPLE_AppDefined,
2512 : "Failed to delete added field %s", pszName);
2513 : }
2514 11 : break;
2515 : }
2516 : }
2517 : }
2518 : else
2519 : {
2520 0 : CPLError(CE_Failure, CPLE_AppDefined,
2521 : "Failed to restore field %s (field not found at index %d)",
2522 : pszName, iField);
2523 : }
2524 : }
2525 :
2526 : // Remove from the storage the deleted fields that have been restored
2527 307 : for (const auto &i : toBeRemoved)
2528 : {
2529 136 : m_apoFieldDefnChanges.erase(m_apoFieldDefnChanges.begin() + i);
2530 : }
2531 :
2532 : /**********************************************************************/
2533 : /* Reset geometry fields to their previous state. */
2534 : /**********************************************************************/
2535 :
2536 171 : bSavepointFound = false;
2537 :
2538 : // Loop through all changed geometry fields and reset them to their previous state.
2539 171 : for (int i = static_cast<int>(m_apoGeomFieldDefnChanges.size()) - 1; i >= 0;
2540 : i--)
2541 : {
2542 0 : auto &oGeomFieldChange = m_apoGeomFieldDefnChanges[i];
2543 :
2544 0 : if (!osSavepointName.empty())
2545 : {
2546 0 : if (oGeomFieldChange.osSavepointName == osSavepointName)
2547 : {
2548 0 : bSavepointFound = true;
2549 : }
2550 0 : else if (bSavepointFound)
2551 : {
2552 0 : continue;
2553 : }
2554 : }
2555 0 : const char *pszName = oGeomFieldChange.poFieldDefn->GetNameRef();
2556 0 : const int iGeomField = oGeomFieldChange.iField;
2557 0 : if (iGeomField >= 0)
2558 : {
2559 0 : switch (oGeomFieldChange.eChangeType)
2560 : {
2561 0 : case FieldChangeType::DELETE_FIELD:
2562 : case FieldChangeType::ALTER_FIELD:
2563 : {
2564 : // Currently not handled by OGR for geometry fields
2565 0 : break;
2566 : }
2567 0 : case FieldChangeType::ADD_FIELD:
2568 : {
2569 : std::unique_ptr<OGRGeomFieldDefn> poGeomFieldDef =
2570 0 : GetLayerDefn()->StealGeomFieldDefn(
2571 0 : oGeomFieldChange.iField);
2572 0 : if (poGeomFieldDef)
2573 : {
2574 : oGeomFieldChange.poFieldDefn =
2575 0 : std::move(poGeomFieldDef);
2576 : }
2577 : else
2578 : {
2579 0 : CPLError(CE_Failure, CPLE_AppDefined,
2580 : "Failed to delete added geometry field %s",
2581 : pszName);
2582 : }
2583 0 : break;
2584 : }
2585 : }
2586 : }
2587 : else
2588 : {
2589 0 : CPLError(CE_Failure, CPLE_AppDefined,
2590 : "Failed to restore geometry field %s (field not found at "
2591 : "index %d)",
2592 : pszName, oGeomFieldChange.iField);
2593 : }
2594 : }
2595 171 : }
2596 :
2597 : //! @endcond
2598 :
2599 : /************************************************************************/
2600 : /* OGR_L_ResetReading() */
2601 : /************************************************************************/
2602 :
2603 17668 : void OGR_L_ResetReading(OGRLayerH hLayer)
2604 :
2605 : {
2606 17668 : VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
2607 :
2608 : #ifdef OGRAPISPY_ENABLED
2609 17668 : if (bOGRAPISpyEnabled)
2610 2 : OGRAPISpy_L_ResetReading(hLayer);
2611 : #endif
2612 :
2613 17668 : OGRLayer::FromHandle(hLayer)->ResetReading();
2614 : }
2615 :
2616 : /************************************************************************/
2617 : /* InitializeIndexSupport() */
2618 : /* */
2619 : /* This is only intended to be called by driver layer */
2620 : /* implementations but we don't make it protected so that the */
2621 : /* datasources can do it too if that is more appropriate. */
2622 : /************************************************************************/
2623 :
2624 : //! @cond Doxygen_Suppress
2625 : OGRErr
2626 650 : OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
2627 :
2628 : {
2629 : #ifdef HAVE_MITAB
2630 : OGRErr eErr;
2631 :
2632 650 : if (m_poAttrIndex != nullptr)
2633 484 : return OGRERR_NONE;
2634 :
2635 166 : m_poAttrIndex = OGRCreateDefaultLayerIndex();
2636 :
2637 166 : eErr = m_poAttrIndex->Initialize(pszFilename, this);
2638 166 : if (eErr != OGRERR_NONE)
2639 : {
2640 0 : delete m_poAttrIndex;
2641 0 : m_poAttrIndex = nullptr;
2642 : }
2643 :
2644 166 : return eErr;
2645 : #else
2646 : return OGRERR_FAILURE;
2647 : #endif
2648 : }
2649 :
2650 : //! @endcond
2651 :
2652 : /************************************************************************/
2653 : /* SyncToDisk() */
2654 : /************************************************************************/
2655 :
2656 4846 : OGRErr OGRLayer::SyncToDisk()
2657 :
2658 : {
2659 4846 : return OGRERR_NONE;
2660 : }
2661 :
2662 : /************************************************************************/
2663 : /* OGR_L_SyncToDisk() */
2664 : /************************************************************************/
2665 :
2666 251 : OGRErr OGR_L_SyncToDisk(OGRLayerH hLayer)
2667 :
2668 : {
2669 251 : VALIDATE_POINTER1(hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE);
2670 :
2671 : #ifdef OGRAPISPY_ENABLED
2672 251 : if (bOGRAPISpyEnabled)
2673 2 : OGRAPISpy_L_SyncToDisk(hLayer);
2674 : #endif
2675 :
2676 251 : return OGRLayer::FromHandle(hLayer)->SyncToDisk();
2677 : }
2678 :
2679 : /************************************************************************/
2680 : /* DeleteFeature() */
2681 : /************************************************************************/
2682 :
2683 320 : OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
2684 : {
2685 320 : return OGRERR_UNSUPPORTED_OPERATION;
2686 : }
2687 :
2688 : /************************************************************************/
2689 : /* OGR_L_DeleteFeature() */
2690 : /************************************************************************/
2691 :
2692 3355 : OGRErr OGR_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
2693 :
2694 : {
2695 3355 : VALIDATE_POINTER1(hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE);
2696 :
2697 : #ifdef OGRAPISPY_ENABLED
2698 3355 : if (bOGRAPISpyEnabled)
2699 2 : OGRAPISpy_L_DeleteFeature(hLayer, nFID);
2700 : #endif
2701 :
2702 3355 : return OGRLayer::FromHandle(hLayer)->DeleteFeature(nFID);
2703 : }
2704 :
2705 : /************************************************************************/
2706 : /* GetFeaturesRead() */
2707 : /************************************************************************/
2708 :
2709 : //! @cond Doxygen_Suppress
2710 0 : GIntBig OGRLayer::GetFeaturesRead()
2711 :
2712 : {
2713 0 : return m_nFeaturesRead;
2714 : }
2715 :
2716 : //! @endcond
2717 :
2718 : /************************************************************************/
2719 : /* OGR_L_GetFeaturesRead() */
2720 : /************************************************************************/
2721 :
2722 0 : GIntBig OGR_L_GetFeaturesRead(OGRLayerH hLayer)
2723 :
2724 : {
2725 0 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeaturesRead", 0);
2726 :
2727 0 : return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
2728 : }
2729 :
2730 : /************************************************************************/
2731 : /* GetFIDColumn */
2732 : /************************************************************************/
2733 :
2734 7515 : const char *OGRLayer::GetFIDColumn()
2735 :
2736 : {
2737 7515 : return "";
2738 : }
2739 :
2740 : /************************************************************************/
2741 : /* OGR_L_GetFIDColumn() */
2742 : /************************************************************************/
2743 :
2744 388 : const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
2745 :
2746 : {
2747 388 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
2748 :
2749 : #ifdef OGRAPISPY_ENABLED
2750 388 : if (bOGRAPISpyEnabled)
2751 2 : OGRAPISpy_L_GetFIDColumn(hLayer);
2752 : #endif
2753 :
2754 388 : return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
2755 : }
2756 :
2757 : /************************************************************************/
2758 : /* GetGeometryColumn() */
2759 : /************************************************************************/
2760 :
2761 3459 : const char *OGRLayer::GetGeometryColumn()
2762 :
2763 : {
2764 3459 : if (GetLayerDefn()->GetGeomFieldCount() > 0)
2765 3379 : return GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef();
2766 : else
2767 80 : return "";
2768 : }
2769 :
2770 : /************************************************************************/
2771 : /* OGR_L_GetGeometryColumn() */
2772 : /************************************************************************/
2773 :
2774 691 : const char *OGR_L_GetGeometryColumn(OGRLayerH hLayer)
2775 :
2776 : {
2777 691 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryColumn", nullptr);
2778 :
2779 : #ifdef OGRAPISPY_ENABLED
2780 691 : if (bOGRAPISpyEnabled)
2781 2 : OGRAPISpy_L_GetGeometryColumn(hLayer);
2782 : #endif
2783 :
2784 691 : return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
2785 : }
2786 :
2787 : /************************************************************************/
2788 : /* GetStyleTable() */
2789 : /************************************************************************/
2790 :
2791 953 : OGRStyleTable *OGRLayer::GetStyleTable()
2792 : {
2793 953 : return m_poStyleTable;
2794 : }
2795 :
2796 : /************************************************************************/
2797 : /* SetStyleTableDirectly() */
2798 : /************************************************************************/
2799 :
2800 0 : void OGRLayer::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
2801 : {
2802 0 : if (m_poStyleTable)
2803 0 : delete m_poStyleTable;
2804 0 : m_poStyleTable = poStyleTable;
2805 0 : }
2806 :
2807 : /************************************************************************/
2808 : /* SetStyleTable() */
2809 : /************************************************************************/
2810 :
2811 950 : void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
2812 : {
2813 950 : if (m_poStyleTable)
2814 0 : delete m_poStyleTable;
2815 950 : if (poStyleTable)
2816 1 : m_poStyleTable = poStyleTable->Clone();
2817 950 : }
2818 :
2819 : /************************************************************************/
2820 : /* OGR_L_GetStyleTable() */
2821 : /************************************************************************/
2822 :
2823 3 : OGRStyleTableH OGR_L_GetStyleTable(OGRLayerH hLayer)
2824 :
2825 : {
2826 3 : VALIDATE_POINTER1(hLayer, "OGR_L_GetStyleTable", nullptr);
2827 :
2828 : return reinterpret_cast<OGRStyleTableH>(
2829 3 : OGRLayer::FromHandle(hLayer)->GetStyleTable());
2830 : }
2831 :
2832 : /************************************************************************/
2833 : /* OGR_L_SetStyleTableDirectly() */
2834 : /************************************************************************/
2835 :
2836 0 : void OGR_L_SetStyleTableDirectly(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
2837 :
2838 : {
2839 0 : VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTableDirectly");
2840 :
2841 0 : OGRLayer::FromHandle(hLayer)->SetStyleTableDirectly(
2842 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
2843 : }
2844 :
2845 : /************************************************************************/
2846 : /* OGR_L_SetStyleTable() */
2847 : /************************************************************************/
2848 :
2849 1 : void OGR_L_SetStyleTable(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
2850 :
2851 : {
2852 1 : VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTable");
2853 1 : VALIDATE_POINTER0(hStyleTable, "OGR_L_SetStyleTable");
2854 :
2855 1 : OGRLayer::FromHandle(hLayer)->SetStyleTable(
2856 1 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
2857 : }
2858 :
2859 : /************************************************************************/
2860 : /* GetName() */
2861 : /************************************************************************/
2862 :
2863 1122670 : const char *OGRLayer::GetName()
2864 :
2865 : {
2866 1122670 : return GetLayerDefn()->GetName();
2867 : }
2868 :
2869 : /************************************************************************/
2870 : /* OGR_L_GetName() */
2871 : /************************************************************************/
2872 :
2873 1384 : const char *OGR_L_GetName(OGRLayerH hLayer)
2874 :
2875 : {
2876 1384 : VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
2877 :
2878 : #ifdef OGRAPISPY_ENABLED
2879 1384 : if (bOGRAPISpyEnabled)
2880 2 : OGRAPISpy_L_GetName(hLayer);
2881 : #endif
2882 :
2883 1384 : return OGRLayer::FromHandle(hLayer)->GetName();
2884 : }
2885 :
2886 : /************************************************************************/
2887 : /* GetGeomType() */
2888 : /************************************************************************/
2889 :
2890 217190 : OGRwkbGeometryType OGRLayer::GetGeomType()
2891 : {
2892 217190 : OGRFeatureDefn *poLayerDefn = GetLayerDefn();
2893 217190 : if (poLayerDefn == nullptr)
2894 : {
2895 0 : CPLDebug("OGR", "GetLayerType() returns NULL !");
2896 0 : return wkbUnknown;
2897 : }
2898 217190 : return poLayerDefn->GetGeomType();
2899 : }
2900 :
2901 : /************************************************************************/
2902 : /* OGR_L_GetGeomType() */
2903 : /************************************************************************/
2904 :
2905 1102 : OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
2906 :
2907 : {
2908 1102 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
2909 :
2910 : #ifdef OGRAPISPY_ENABLED
2911 1102 : if (bOGRAPISpyEnabled)
2912 2 : OGRAPISpy_L_GetGeomType(hLayer);
2913 : #endif
2914 :
2915 1102 : OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
2916 1102 : if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
2917 : {
2918 1 : eType = OGR_GT_GetLinear(eType);
2919 : }
2920 1102 : return eType;
2921 : }
2922 :
2923 : /************************************************************************/
2924 : /* SetIgnoredFields() */
2925 : /************************************************************************/
2926 :
2927 8403 : OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
2928 : {
2929 8403 : OGRFeatureDefn *poDefn = GetLayerDefn();
2930 :
2931 : // first set everything as *not* ignored
2932 63208 : for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
2933 : {
2934 54805 : poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
2935 : }
2936 19463 : for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
2937 : {
2938 11060 : poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
2939 : }
2940 8403 : poDefn->SetStyleIgnored(FALSE);
2941 :
2942 : // ignore some fields
2943 15882 : for (const char *pszFieldName : cpl::Iterate(papszFields))
2944 : {
2945 : // check special fields
2946 7479 : if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
2947 154 : poDefn->SetGeometryIgnored(TRUE);
2948 7325 : else if (EQUAL(pszFieldName, "OGR_STYLE"))
2949 13 : poDefn->SetStyleIgnored(TRUE);
2950 : else
2951 : {
2952 : // check ordinary fields
2953 7312 : int iField = poDefn->GetFieldIndex(pszFieldName);
2954 7312 : if (iField == -1)
2955 : {
2956 : // check geometry field
2957 1638 : iField = poDefn->GetGeomFieldIndex(pszFieldName);
2958 1638 : if (iField == -1)
2959 : {
2960 0 : return OGRERR_FAILURE;
2961 : }
2962 : else
2963 1638 : poDefn->GetGeomFieldDefn(iField)->SetIgnored(TRUE);
2964 : }
2965 : else
2966 5674 : poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
2967 : }
2968 : }
2969 :
2970 8403 : return OGRERR_NONE;
2971 : }
2972 :
2973 : /************************************************************************/
2974 : /* OGR_L_SetIgnoredFields() */
2975 : /************************************************************************/
2976 :
2977 265 : OGRErr OGR_L_SetIgnoredFields(OGRLayerH hLayer, const char **papszFields)
2978 :
2979 : {
2980 265 : VALIDATE_POINTER1(hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE);
2981 :
2982 : #ifdef OGRAPISPY_ENABLED
2983 265 : if (bOGRAPISpyEnabled)
2984 2 : OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
2985 : #endif
2986 :
2987 265 : return OGRLayer::FromHandle(hLayer)->SetIgnoredFields(papszFields);
2988 : }
2989 :
2990 : /************************************************************************/
2991 : /* Rename() */
2992 : /************************************************************************/
2993 :
2994 : /** Rename layer.
2995 : *
2996 : * This operation is implemented only by layers that expose the OLCRename
2997 : * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
2998 : *
2999 : * This operation will fail if a layer with the new name already exists.
3000 : *
3001 : * On success, GetDescription() and GetLayerDefn()->GetName() will return
3002 : * pszNewName.
3003 : *
3004 : * Renaming the layer may interrupt current feature iteration.
3005 : *
3006 : * @param pszNewName New layer name. Must not be NULL.
3007 : * @return OGRERR_NONE in case of success
3008 : *
3009 : * @since GDAL 3.5
3010 : */
3011 0 : OGRErr OGRLayer::Rename(CPL_UNUSED const char *pszNewName)
3012 : {
3013 0 : CPLError(CE_Failure, CPLE_NotSupported,
3014 : "Rename() not supported by this layer.");
3015 :
3016 0 : return OGRERR_UNSUPPORTED_OPERATION;
3017 : }
3018 :
3019 : /************************************************************************/
3020 : /* OGR_L_Rename() */
3021 : /************************************************************************/
3022 :
3023 : /** Rename layer.
3024 : *
3025 : * This operation is implemented only by layers that expose the OLCRename
3026 : * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
3027 : *
3028 : * This operation will fail if a layer with the new name already exists.
3029 : *
3030 : * On success, GetDescription() and GetLayerDefn()->GetName() will return
3031 : * pszNewName.
3032 : *
3033 : * Renaming the layer may interrupt current feature iteration.
3034 : *
3035 : * @param hLayer Layer to rename.
3036 : * @param pszNewName New layer name. Must not be NULL.
3037 : * @return OGRERR_NONE in case of success
3038 : *
3039 : * @since GDAL 3.5
3040 : */
3041 29 : OGRErr OGR_L_Rename(OGRLayerH hLayer, const char *pszNewName)
3042 :
3043 : {
3044 29 : VALIDATE_POINTER1(hLayer, "OGR_L_Rename", OGRERR_INVALID_HANDLE);
3045 29 : VALIDATE_POINTER1(pszNewName, "OGR_L_Rename", OGRERR_FAILURE);
3046 :
3047 29 : return OGRLayer::FromHandle(hLayer)->Rename(pszNewName);
3048 : }
3049 :
3050 : /************************************************************************/
3051 : /* helper functions for layer overlay methods */
3052 : /************************************************************************/
3053 :
3054 50 : static OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
3055 : {
3056 50 : OGRErr ret = OGRERR_NONE;
3057 50 : OGRGeometry *g = pLayer->GetSpatialFilter();
3058 50 : *ppGeometry = g ? g->clone() : nullptr;
3059 50 : return ret;
3060 : }
3061 :
3062 69 : static OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
3063 : {
3064 69 : OGRErr ret = OGRERR_NONE;
3065 69 : int n = poDefn->GetFieldCount();
3066 69 : if (n > 0)
3067 : {
3068 41 : *map = static_cast<int *>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
3069 41 : if (!(*map))
3070 0 : return OGRERR_NOT_ENOUGH_MEMORY;
3071 115 : for (int i = 0; i < n; i++)
3072 74 : (*map)[i] = -1;
3073 : }
3074 69 : return ret;
3075 : }
3076 :
3077 39 : static OGRErr set_result_schema(OGRLayer *pLayerResult,
3078 : OGRFeatureDefn *poDefnInput,
3079 : OGRFeatureDefn *poDefnMethod, int *mapInput,
3080 : int *mapMethod, bool combined,
3081 : const char *const *papszOptions)
3082 : {
3083 39 : OGRErr ret = OGRERR_NONE;
3084 39 : OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
3085 : const char *pszInputPrefix =
3086 39 : CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
3087 : const char *pszMethodPrefix =
3088 39 : CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
3089 : int bSkipFailures =
3090 39 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3091 39 : if (poDefnResult->GetFieldCount() > 0)
3092 : {
3093 : // the user has defined the schema of the output layer
3094 4 : if (mapInput)
3095 : {
3096 9 : for (int iField = 0; iField < poDefnInput->GetFieldCount();
3097 : iField++)
3098 : {
3099 : CPLString osName(
3100 5 : poDefnInput->GetFieldDefn(iField)->GetNameRef());
3101 5 : if (pszInputPrefix != nullptr)
3102 0 : osName = pszInputPrefix + osName;
3103 5 : mapInput[iField] = poDefnResult->GetFieldIndex(osName);
3104 : }
3105 : }
3106 4 : if (!mapMethod)
3107 2 : return ret;
3108 : // cppcheck-suppress nullPointer
3109 5 : for (int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++)
3110 : {
3111 : // cppcheck-suppress nullPointer
3112 3 : CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
3113 3 : if (pszMethodPrefix != nullptr)
3114 0 : osName = pszMethodPrefix + osName;
3115 3 : mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
3116 : }
3117 : }
3118 : else
3119 : {
3120 : // use schema from the input layer or from input and method layers
3121 35 : int nFieldsInput = poDefnInput->GetFieldCount();
3122 :
3123 : // If no prefix is specified and we have input+method layers, make
3124 : // sure we will generate unique field names
3125 35 : std::set<std::string> oSetInputFieldNames;
3126 35 : std::set<std::string> oSetMethodFieldNames;
3127 35 : if (poDefnMethod != nullptr && pszInputPrefix == nullptr &&
3128 : pszMethodPrefix == nullptr)
3129 : {
3130 56 : for (int iField = 0; iField < nFieldsInput; iField++)
3131 : {
3132 : oSetInputFieldNames.insert(
3133 28 : poDefnInput->GetFieldDefn(iField)->GetNameRef());
3134 : }
3135 28 : const int nFieldsMethod = poDefnMethod->GetFieldCount();
3136 54 : for (int iField = 0; iField < nFieldsMethod; iField++)
3137 : {
3138 : oSetMethodFieldNames.insert(
3139 26 : poDefnMethod->GetFieldDefn(iField)->GetNameRef());
3140 : }
3141 : }
3142 :
3143 75 : for (int iField = 0; iField < nFieldsInput; iField++)
3144 : {
3145 40 : OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
3146 40 : if (pszInputPrefix != nullptr)
3147 0 : oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix,
3148 : oFieldDefn.GetNameRef()));
3149 66 : else if (!oSetMethodFieldNames.empty() &&
3150 66 : oSetMethodFieldNames.find(oFieldDefn.GetNameRef()) !=
3151 66 : oSetMethodFieldNames.end())
3152 : {
3153 : // Field of same name present in method layer
3154 17 : oFieldDefn.SetName(
3155 : CPLSPrintf("input_%s", oFieldDefn.GetNameRef()));
3156 : }
3157 40 : ret = pLayerResult->CreateField(&oFieldDefn);
3158 40 : if (ret != OGRERR_NONE)
3159 : {
3160 0 : if (!bSkipFailures)
3161 0 : return ret;
3162 : else
3163 : {
3164 0 : CPLErrorReset();
3165 0 : ret = OGRERR_NONE;
3166 : }
3167 : }
3168 40 : if (mapInput)
3169 40 : mapInput[iField] = iField;
3170 : }
3171 35 : if (!combined)
3172 11 : return ret;
3173 24 : if (!mapMethod)
3174 12 : return ret;
3175 12 : if (!poDefnMethod)
3176 0 : return ret;
3177 12 : const int nFieldsMethod = poDefnMethod->GetFieldCount();
3178 34 : for (int iField = 0; iField < nFieldsMethod; iField++)
3179 : {
3180 22 : OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
3181 22 : if (pszMethodPrefix != nullptr)
3182 0 : oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix,
3183 : oFieldDefn.GetNameRef()));
3184 44 : else if (!oSetInputFieldNames.empty() &&
3185 44 : oSetInputFieldNames.find(oFieldDefn.GetNameRef()) !=
3186 44 : oSetInputFieldNames.end())
3187 : {
3188 : // Field of same name present in method layer
3189 15 : oFieldDefn.SetName(
3190 : CPLSPrintf("method_%s", oFieldDefn.GetNameRef()));
3191 : }
3192 22 : ret = pLayerResult->CreateField(&oFieldDefn);
3193 22 : if (ret != OGRERR_NONE)
3194 : {
3195 0 : if (!bSkipFailures)
3196 0 : return ret;
3197 : else
3198 : {
3199 0 : CPLErrorReset();
3200 0 : ret = OGRERR_NONE;
3201 : }
3202 : }
3203 22 : mapMethod[iField] = nFieldsInput + iField;
3204 : }
3205 : }
3206 14 : return ret;
3207 : }
3208 :
3209 91 : static OGRGeometry *set_filter_from(OGRLayer *pLayer,
3210 : OGRGeometry *pGeometryExistingFilter,
3211 : OGRFeature *pFeature)
3212 : {
3213 91 : OGRGeometry *geom = pFeature->GetGeometryRef();
3214 91 : if (!geom)
3215 0 : return nullptr;
3216 91 : if (pGeometryExistingFilter)
3217 : {
3218 0 : if (!geom->Intersects(pGeometryExistingFilter))
3219 0 : return nullptr;
3220 0 : OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
3221 0 : if (intersection)
3222 : {
3223 0 : pLayer->SetSpatialFilter(intersection);
3224 0 : delete intersection;
3225 : }
3226 : else
3227 0 : return nullptr;
3228 : }
3229 : else
3230 : {
3231 91 : pLayer->SetSpatialFilter(geom);
3232 : }
3233 91 : return geom;
3234 : }
3235 :
3236 23 : static OGRGeometry *promote_to_multi(OGRGeometry *poGeom)
3237 : {
3238 23 : OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
3239 23 : if (eType == wkbPoint)
3240 1 : return OGRGeometryFactory::forceToMultiPoint(poGeom);
3241 22 : else if (eType == wkbPolygon)
3242 22 : return OGRGeometryFactory::forceToMultiPolygon(poGeom);
3243 0 : else if (eType == wkbLineString)
3244 0 : return OGRGeometryFactory::forceToMultiLineString(poGeom);
3245 : else
3246 0 : return poGeom;
3247 : }
3248 :
3249 : /************************************************************************/
3250 : /* Intersection() */
3251 : /************************************************************************/
3252 : /**
3253 : * \brief Intersection of two layers.
3254 : *
3255 : * The result layer contains features whose geometries represent areas
3256 : * that are common between features in the input layer and in the
3257 : * method layer. The features in the result layer have attributes from
3258 : * both input and method layers. The schema of the result layer can be
3259 : * set by the user or, if it is empty, is initialized to contain all
3260 : * fields in the input and method layers.
3261 : *
3262 : * \note If the schema of the result is set by user and contains
3263 : * fields that have the same name as a field in input and in method
3264 : * layer, then the attribute in the result feature will get the value
3265 : * from the feature of the method layer.
3266 : *
3267 : * \note For best performance use the minimum amount of features in
3268 : * the method layer and copy it into a memory layer.
3269 : *
3270 : * \note This method relies on GEOS support. Do not use unless the
3271 : * GEOS support is compiled in.
3272 : *
3273 : * The recognized list of options is:
3274 : * <ul>
3275 : * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
3276 : * feature could not be inserted or a GEOS call failed.
3277 : * </li>
3278 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3279 : * into MultiPolygons, LineStrings to MultiLineStrings or
3280 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
3281 : * </li>
3282 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3283 : * will be created from the fields of the input layer.
3284 : * </li>
3285 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3286 : * will be created from the fields of the method layer.
3287 : * </li>
3288 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3289 : * geometries to pretest intersection of features of method layer
3290 : * with features of this layer.
3291 : * </li>
3292 : * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
3293 : * containment of features of method layer within the features of
3294 : * this layer. This will speed up the method significantly in some
3295 : * cases. Requires that the prepared geometries are in effect.
3296 : * </li>
3297 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3298 : * result features with lower dimension geometry that would
3299 : * otherwise be added to the result layer. The default is YES, to add
3300 : * features with lower dimension geometry, but only if the result layer
3301 : * has an unknown geometry type.
3302 : * </li>
3303 : * </ul>
3304 : *
3305 : * This method is the same as the C function OGR_L_Intersection().
3306 : *
3307 : * @param pLayerMethod the method layer. Should not be NULL.
3308 : *
3309 : * @param pLayerResult the layer where the features resulting from the
3310 : * operation are inserted. Should not be NULL. See above the note
3311 : * about the schema.
3312 : *
3313 : * @param papszOptions NULL terminated list of options (may be NULL).
3314 : *
3315 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3316 : * reporting progress or NULL.
3317 : *
3318 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3319 : *
3320 : * @return an error code if there was an error or the execution was
3321 : * interrupted, OGRERR_NONE otherwise.
3322 : *
3323 : * @note The first geometry field is always used.
3324 : *
3325 : * @since OGR 1.10
3326 : */
3327 :
3328 8 : OGRErr OGRLayer::Intersection(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
3329 : char **papszOptions, GDALProgressFunc pfnProgress,
3330 : void *pProgressArg)
3331 : {
3332 8 : OGRErr ret = OGRERR_NONE;
3333 8 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
3334 8 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3335 8 : OGRFeatureDefn *poDefnResult = nullptr;
3336 8 : OGRGeometry *pGeometryMethodFilter = nullptr;
3337 8 : int *mapInput = nullptr;
3338 8 : int *mapMethod = nullptr;
3339 8 : OGREnvelope sEnvelopeMethod;
3340 : GBool bEnvelopeSet;
3341 8 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
3342 8 : double progress_counter = 0;
3343 8 : double progress_ticker = 0;
3344 : const bool bSkipFailures =
3345 8 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3346 8 : const bool bPromoteToMulti = CPLTestBool(
3347 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3348 8 : const bool bUsePreparedGeometries = CPLTestBool(
3349 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
3350 8 : const bool bPretestContainment = CPLTestBool(
3351 : CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
3352 8 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
3353 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
3354 :
3355 : // check for GEOS
3356 8 : if (!OGRGeometryFactory::haveGEOS())
3357 : {
3358 0 : CPLError(CE_Failure, CPLE_AppDefined,
3359 : "OGRLayer::Intersection() requires GEOS support");
3360 0 : return OGRERR_UNSUPPORTED_OPERATION;
3361 : }
3362 :
3363 : // get resources
3364 8 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3365 8 : if (ret != OGRERR_NONE)
3366 0 : goto done;
3367 8 : ret = create_field_map(poDefnInput, &mapInput);
3368 8 : if (ret != OGRERR_NONE)
3369 0 : goto done;
3370 8 : ret = create_field_map(poDefnMethod, &mapMethod);
3371 8 : if (ret != OGRERR_NONE)
3372 0 : goto done;
3373 8 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
3374 : mapMethod, true, papszOptions);
3375 8 : if (ret != OGRERR_NONE)
3376 0 : goto done;
3377 8 : poDefnResult = pLayerResult->GetLayerDefn();
3378 8 : bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
3379 8 : if (bKeepLowerDimGeom)
3380 : {
3381 : // require that the result layer is of geom type unknown
3382 6 : if (pLayerResult->GetGeomType() != wkbUnknown)
3383 : {
3384 1 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
3385 : "since the result layer does not allow it.");
3386 1 : bKeepLowerDimGeom = false;
3387 : }
3388 : }
3389 :
3390 22 : for (auto &&x : this)
3391 : {
3392 :
3393 14 : if (pfnProgress)
3394 : {
3395 3 : double p = progress_counter / progress_max;
3396 3 : if (p > progress_ticker)
3397 : {
3398 1 : if (!pfnProgress(p, "", pProgressArg))
3399 : {
3400 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3401 0 : ret = OGRERR_FAILURE;
3402 0 : goto done;
3403 : }
3404 : }
3405 3 : progress_counter += 1.0;
3406 : }
3407 :
3408 : // is it worth to proceed?
3409 14 : if (bEnvelopeSet)
3410 : {
3411 14 : OGRGeometry *x_geom = x->GetGeometryRef();
3412 14 : if (x_geom)
3413 : {
3414 14 : OGREnvelope x_env;
3415 14 : x_geom->getEnvelope(&x_env);
3416 14 : if (x_env.MaxX < sEnvelopeMethod.MinX ||
3417 14 : x_env.MaxY < sEnvelopeMethod.MinY ||
3418 14 : sEnvelopeMethod.MaxX < x_env.MinX ||
3419 14 : sEnvelopeMethod.MaxY < x_env.MinY)
3420 : {
3421 0 : continue;
3422 : }
3423 : }
3424 : else
3425 : {
3426 0 : continue;
3427 : }
3428 : }
3429 :
3430 : // set up the filter for method layer
3431 14 : CPLErrorReset();
3432 : OGRGeometry *x_geom =
3433 14 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3434 14 : if (CPLGetLastErrorType() != CE_None)
3435 : {
3436 0 : if (!bSkipFailures)
3437 : {
3438 0 : ret = OGRERR_FAILURE;
3439 0 : goto done;
3440 : }
3441 : else
3442 : {
3443 0 : CPLErrorReset();
3444 0 : ret = OGRERR_NONE;
3445 : }
3446 : }
3447 14 : if (!x_geom)
3448 : {
3449 0 : continue;
3450 : }
3451 :
3452 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
3453 14 : if (bUsePreparedGeometries)
3454 : {
3455 14 : x_prepared_geom.reset(
3456 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
3457 14 : if (!x_prepared_geom)
3458 : {
3459 0 : goto done;
3460 : }
3461 : }
3462 :
3463 30 : for (auto &&y : pLayerMethod)
3464 : {
3465 16 : OGRGeometry *y_geom = y->GetGeometryRef();
3466 16 : if (!y_geom)
3467 4 : continue;
3468 0 : OGRGeometryUniquePtr z_geom;
3469 :
3470 16 : if (x_prepared_geom)
3471 : {
3472 16 : CPLErrorReset();
3473 16 : ret = OGRERR_NONE;
3474 16 : if (bPretestContainment &&
3475 0 : OGRPreparedGeometryContains(x_prepared_geom.get(),
3476 : OGRGeometry::ToHandle(y_geom)))
3477 : {
3478 0 : if (CPLGetLastErrorType() == CE_None)
3479 0 : z_geom.reset(y_geom->clone());
3480 : }
3481 16 : else if (!(OGRPreparedGeometryIntersects(
3482 : x_prepared_geom.get(),
3483 : OGRGeometry::ToHandle(y_geom))))
3484 : {
3485 0 : if (CPLGetLastErrorType() == CE_None)
3486 : {
3487 0 : continue;
3488 : }
3489 : }
3490 16 : if (CPLGetLastErrorType() != CE_None)
3491 : {
3492 0 : if (!bSkipFailures)
3493 : {
3494 0 : ret = OGRERR_FAILURE;
3495 0 : goto done;
3496 : }
3497 : else
3498 : {
3499 0 : CPLErrorReset();
3500 0 : ret = OGRERR_NONE;
3501 0 : continue;
3502 : }
3503 : }
3504 : }
3505 16 : if (!z_geom)
3506 : {
3507 16 : CPLErrorReset();
3508 16 : z_geom.reset(x_geom->Intersection(y_geom));
3509 16 : if (CPLGetLastErrorType() != CE_None || z_geom == nullptr)
3510 : {
3511 0 : if (!bSkipFailures)
3512 : {
3513 0 : ret = OGRERR_FAILURE;
3514 0 : goto done;
3515 : }
3516 : else
3517 : {
3518 0 : CPLErrorReset();
3519 0 : ret = OGRERR_NONE;
3520 0 : continue;
3521 : }
3522 : }
3523 32 : if (z_geom->IsEmpty() ||
3524 16 : (!bKeepLowerDimGeom &&
3525 7 : (x_geom->getDimension() == y_geom->getDimension() &&
3526 7 : z_geom->getDimension() < x_geom->getDimension())))
3527 : {
3528 4 : continue;
3529 : }
3530 : }
3531 12 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3532 12 : z->SetFieldsFrom(x.get(), mapInput);
3533 12 : z->SetFieldsFrom(y.get(), mapMethod);
3534 12 : if (bPromoteToMulti)
3535 3 : z_geom.reset(promote_to_multi(z_geom.release()));
3536 12 : z->SetGeometryDirectly(z_geom.release());
3537 12 : ret = pLayerResult->CreateFeature(z.get());
3538 :
3539 12 : if (ret != OGRERR_NONE)
3540 : {
3541 0 : if (!bSkipFailures)
3542 : {
3543 0 : goto done;
3544 : }
3545 : else
3546 : {
3547 0 : CPLErrorReset();
3548 0 : ret = OGRERR_NONE;
3549 : }
3550 : }
3551 : }
3552 : }
3553 8 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
3554 : {
3555 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3556 0 : ret = OGRERR_FAILURE;
3557 0 : goto done;
3558 : }
3559 8 : done:
3560 : // release resources
3561 8 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3562 8 : if (pGeometryMethodFilter)
3563 0 : delete pGeometryMethodFilter;
3564 8 : if (mapInput)
3565 4 : VSIFree(mapInput);
3566 8 : if (mapMethod)
3567 4 : VSIFree(mapMethod);
3568 8 : return ret;
3569 : }
3570 :
3571 : /************************************************************************/
3572 : /* OGR_L_Intersection() */
3573 : /************************************************************************/
3574 : /**
3575 : * \brief Intersection of two layers.
3576 : *
3577 : * The result layer contains features whose geometries represent areas
3578 : * that are common between features in the input layer and in the
3579 : * method layer. The features in the result layer have attributes from
3580 : * both input and method layers. The schema of the result layer can be
3581 : * set by the user or, if it is empty, is initialized to contain all
3582 : * fields in the input and method layers.
3583 : *
3584 : * \note If the schema of the result is set by user and contains
3585 : * fields that have the same name as a field in input and in method
3586 : * layer, then the attribute in the result feature will get the value
3587 : * from the feature of the method layer.
3588 : *
3589 : * \note For best performance use the minimum amount of features in
3590 : * the method layer and copy it into a memory layer.
3591 : *
3592 : * \note This method relies on GEOS support. Do not use unless the
3593 : * GEOS support is compiled in.
3594 : *
3595 : * The recognized list of options is :
3596 : * <ul>
3597 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3598 : * feature could not be inserted or a GEOS call failed.
3599 : * </li>
3600 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3601 : * into MultiPolygons, LineStrings to MultiLineStrings or
3602 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
3603 : * </li>
3604 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3605 : * will be created from the fields of the input layer.
3606 : * </li>
3607 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3608 : * will be created from the fields of the method layer.
3609 : * </li>
3610 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3611 : * geometries to pretest intersection of features of method layer
3612 : * with features of this layer.
3613 : * </li>
3614 : * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
3615 : * containment of features of method layer within the features of
3616 : * this layer. This will speed up the method significantly in some
3617 : * cases. Requires that the prepared geometries are in effect.
3618 : * </li>
3619 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3620 : * result features with lower dimension geometry that would
3621 : * otherwise be added to the result layer. The default is YES, to add
3622 : * features with lower dimension geometry, but only if the result layer
3623 : * has an unknown geometry type.
3624 : * </li>
3625 : * </ul>
3626 : *
3627 : * This function is the same as the C++ method OGRLayer::Intersection().
3628 : *
3629 : * @param pLayerInput the input layer. Should not be NULL.
3630 : *
3631 : * @param pLayerMethod the method layer. Should not be NULL.
3632 : *
3633 : * @param pLayerResult the layer where the features resulting from the
3634 : * operation are inserted. Should not be NULL. See above the note
3635 : * about the schema.
3636 : *
3637 : * @param papszOptions NULL terminated list of options (may be NULL).
3638 : *
3639 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3640 : * reporting progress or NULL.
3641 : *
3642 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3643 : *
3644 : * @return an error code if there was an error or the execution was
3645 : * interrupted, OGRERR_NONE otherwise.
3646 : *
3647 : * @note The first geometry field is always used.
3648 : *
3649 : * @since OGR 1.10
3650 : */
3651 :
3652 8 : OGRErr OGR_L_Intersection(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
3653 : OGRLayerH pLayerResult, char **papszOptions,
3654 : GDALProgressFunc pfnProgress, void *pProgressArg)
3655 :
3656 : {
3657 8 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE);
3658 8 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Intersection",
3659 : OGRERR_INVALID_HANDLE);
3660 8 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Intersection",
3661 : OGRERR_INVALID_HANDLE);
3662 :
3663 : return OGRLayer::FromHandle(pLayerInput)
3664 8 : ->Intersection(OGRLayer::FromHandle(pLayerMethod),
3665 : OGRLayer::FromHandle(pLayerResult), papszOptions,
3666 8 : pfnProgress, pProgressArg);
3667 : }
3668 :
3669 : /************************************************************************/
3670 : /* Union() */
3671 : /************************************************************************/
3672 :
3673 : /**
3674 : * \brief Union of two layers.
3675 : *
3676 : * The result layer contains features whose geometries represent areas
3677 : * that are either in the input layer, in the method layer, or in
3678 : * both. The features in the result layer have attributes from both
3679 : * input and method layers. For features which represent areas that
3680 : * are only in the input or in the method layer the respective
3681 : * attributes have undefined values. The schema of the result layer
3682 : * can be set by the user or, if it is empty, is initialized to
3683 : * contain all fields in the input and method layers.
3684 : *
3685 : * \note If the schema of the result is set by user and contains
3686 : * fields that have the same name as a field in input and in method
3687 : * layer, then the attribute in the result feature will get the value
3688 : * from the feature of the method layer (even if it is undefined).
3689 : *
3690 : * \note For best performance use the minimum amount of features in
3691 : * the method layer and copy it into a memory layer.
3692 : *
3693 : * \note This method relies on GEOS support. Do not use unless the
3694 : * GEOS support is compiled in.
3695 : *
3696 : * The recognized list of options is :
3697 : * <ul>
3698 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3699 : * feature could not be inserted or a GEOS call failed.
3700 : * </li>
3701 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3702 : * into MultiPolygons, LineStrings to MultiLineStrings or
3703 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
3704 : * </li>
3705 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3706 : * will be created from the fields of the input layer.
3707 : * </li>
3708 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3709 : * will be created from the fields of the method layer.
3710 : * </li>
3711 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3712 : * geometries to pretest intersection of features of method layer
3713 : * with features of this layer.
3714 : * </li>
3715 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3716 : * result features with lower dimension geometry that would
3717 : * otherwise be added to the result layer. The default is YES, to add
3718 : * features with lower dimension geometry, but only if the result layer
3719 : * has an unknown geometry type.
3720 : * </li>
3721 : * </ul>
3722 : *
3723 : * This method is the same as the C function OGR_L_Union().
3724 : *
3725 : * @param pLayerMethod the method layer. Should not be NULL.
3726 : *
3727 : * @param pLayerResult the layer where the features resulting from the
3728 : * operation are inserted. Should not be NULL. See above the note
3729 : * about the schema.
3730 : *
3731 : * @param papszOptions NULL terminated list of options (may be NULL).
3732 : *
3733 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3734 : * reporting progress or NULL.
3735 : *
3736 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3737 : *
3738 : * @return an error code if there was an error or the execution was
3739 : * interrupted, OGRERR_NONE otherwise.
3740 : *
3741 : * @note The first geometry field is always used.
3742 : *
3743 : * @since OGR 1.10
3744 : */
3745 :
3746 7 : OGRErr OGRLayer::Union(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
3747 : char **papszOptions, GDALProgressFunc pfnProgress,
3748 : void *pProgressArg)
3749 : {
3750 7 : OGRErr ret = OGRERR_NONE;
3751 7 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
3752 7 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3753 7 : OGRFeatureDefn *poDefnResult = nullptr;
3754 7 : OGRGeometry *pGeometryMethodFilter = nullptr;
3755 7 : OGRGeometry *pGeometryInputFilter = nullptr;
3756 7 : int *mapInput = nullptr;
3757 7 : int *mapMethod = nullptr;
3758 : double progress_max =
3759 7 : static_cast<double>(GetFeatureCount(FALSE)) +
3760 7 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
3761 7 : double progress_counter = 0;
3762 7 : double progress_ticker = 0;
3763 : const bool bSkipFailures =
3764 7 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3765 7 : const bool bPromoteToMulti = CPLTestBool(
3766 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3767 7 : const bool bUsePreparedGeometries = CPLTestBool(
3768 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
3769 7 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
3770 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
3771 :
3772 : // check for GEOS
3773 7 : if (!OGRGeometryFactory::haveGEOS())
3774 : {
3775 0 : CPLError(CE_Failure, CPLE_AppDefined,
3776 : "OGRLayer::Union() requires GEOS support");
3777 0 : return OGRERR_UNSUPPORTED_OPERATION;
3778 : }
3779 :
3780 : // get resources
3781 7 : ret = clone_spatial_filter(this, &pGeometryInputFilter);
3782 7 : if (ret != OGRERR_NONE)
3783 0 : goto done;
3784 7 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3785 7 : if (ret != OGRERR_NONE)
3786 0 : goto done;
3787 7 : ret = create_field_map(poDefnInput, &mapInput);
3788 7 : if (ret != OGRERR_NONE)
3789 0 : goto done;
3790 7 : ret = create_field_map(poDefnMethod, &mapMethod);
3791 7 : if (ret != OGRERR_NONE)
3792 0 : goto done;
3793 7 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
3794 : mapMethod, true, papszOptions);
3795 7 : if (ret != OGRERR_NONE)
3796 0 : goto done;
3797 7 : poDefnResult = pLayerResult->GetLayerDefn();
3798 7 : if (bKeepLowerDimGeom)
3799 : {
3800 : // require that the result layer is of geom type unknown
3801 5 : if (pLayerResult->GetGeomType() != wkbUnknown)
3802 : {
3803 0 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
3804 : "since the result layer does not allow it.");
3805 0 : bKeepLowerDimGeom = FALSE;
3806 : }
3807 : }
3808 :
3809 : // add features based on input layer
3810 20 : for (auto &&x : this)
3811 : {
3812 :
3813 13 : if (pfnProgress)
3814 : {
3815 2 : double p = progress_counter / progress_max;
3816 2 : if (p > progress_ticker)
3817 : {
3818 1 : if (!pfnProgress(p, "", pProgressArg))
3819 : {
3820 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3821 0 : ret = OGRERR_FAILURE;
3822 0 : goto done;
3823 : }
3824 : }
3825 2 : progress_counter += 1.0;
3826 : }
3827 :
3828 : // set up the filter on method layer
3829 13 : CPLErrorReset();
3830 : OGRGeometry *x_geom =
3831 13 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3832 13 : if (CPLGetLastErrorType() != CE_None)
3833 : {
3834 0 : if (!bSkipFailures)
3835 : {
3836 0 : ret = OGRERR_FAILURE;
3837 0 : goto done;
3838 : }
3839 : else
3840 : {
3841 0 : CPLErrorReset();
3842 0 : ret = OGRERR_NONE;
3843 : }
3844 : }
3845 13 : if (!x_geom)
3846 : {
3847 0 : continue;
3848 : }
3849 :
3850 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
3851 13 : if (bUsePreparedGeometries)
3852 : {
3853 13 : x_prepared_geom.reset(
3854 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
3855 13 : if (!x_prepared_geom)
3856 : {
3857 0 : goto done;
3858 : }
3859 : }
3860 :
3861 : OGRGeometryUniquePtr x_geom_diff(
3862 : x_geom
3863 13 : ->clone()); // this will be the geometry of the result feature
3864 28 : for (auto &&y : pLayerMethod)
3865 : {
3866 15 : OGRGeometry *y_geom = y->GetGeometryRef();
3867 15 : if (!y_geom)
3868 : {
3869 0 : continue;
3870 : }
3871 :
3872 15 : CPLErrorReset();
3873 30 : if (x_prepared_geom &&
3874 15 : !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
3875 15 : OGRGeometry::ToHandle(y_geom))))
3876 : {
3877 0 : if (CPLGetLastErrorType() == CE_None)
3878 : {
3879 0 : continue;
3880 : }
3881 : }
3882 15 : if (CPLGetLastErrorType() != CE_None)
3883 : {
3884 0 : if (!bSkipFailures)
3885 : {
3886 0 : ret = OGRERR_FAILURE;
3887 0 : goto done;
3888 : }
3889 : else
3890 : {
3891 0 : CPLErrorReset();
3892 0 : ret = OGRERR_NONE;
3893 : }
3894 : }
3895 :
3896 15 : CPLErrorReset();
3897 15 : OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
3898 15 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
3899 : {
3900 0 : if (!bSkipFailures)
3901 : {
3902 0 : ret = OGRERR_FAILURE;
3903 0 : goto done;
3904 : }
3905 : else
3906 : {
3907 0 : CPLErrorReset();
3908 0 : ret = OGRERR_NONE;
3909 0 : continue;
3910 : }
3911 : }
3912 30 : if (poIntersection->IsEmpty() ||
3913 15 : (!bKeepLowerDimGeom &&
3914 6 : (x_geom->getDimension() == y_geom->getDimension() &&
3915 6 : poIntersection->getDimension() < x_geom->getDimension())))
3916 : {
3917 : // ok
3918 : }
3919 : else
3920 : {
3921 11 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3922 11 : z->SetFieldsFrom(x.get(), mapInput);
3923 11 : z->SetFieldsFrom(y.get(), mapMethod);
3924 11 : if (bPromoteToMulti)
3925 2 : poIntersection.reset(
3926 : promote_to_multi(poIntersection.release()));
3927 11 : z->SetGeometryDirectly(poIntersection.release());
3928 :
3929 11 : if (x_geom_diff)
3930 : {
3931 11 : CPLErrorReset();
3932 : OGRGeometryUniquePtr x_geom_diff_new(
3933 11 : x_geom_diff->Difference(y_geom));
3934 22 : if (CPLGetLastErrorType() != CE_None ||
3935 11 : x_geom_diff_new == nullptr)
3936 : {
3937 0 : if (!bSkipFailures)
3938 : {
3939 0 : ret = OGRERR_FAILURE;
3940 0 : goto done;
3941 : }
3942 : else
3943 : {
3944 0 : CPLErrorReset();
3945 : }
3946 : }
3947 : else
3948 : {
3949 11 : x_geom_diff.swap(x_geom_diff_new);
3950 : }
3951 : }
3952 :
3953 11 : ret = pLayerResult->CreateFeature(z.get());
3954 11 : if (ret != OGRERR_NONE)
3955 : {
3956 0 : if (!bSkipFailures)
3957 : {
3958 0 : goto done;
3959 : }
3960 : else
3961 : {
3962 0 : CPLErrorReset();
3963 0 : ret = OGRERR_NONE;
3964 : }
3965 : }
3966 : }
3967 : }
3968 13 : x_prepared_geom.reset();
3969 :
3970 13 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
3971 : {
3972 : // ok
3973 : }
3974 : else
3975 : {
3976 11 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3977 11 : z->SetFieldsFrom(x.get(), mapInput);
3978 11 : if (bPromoteToMulti)
3979 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
3980 11 : z->SetGeometryDirectly(x_geom_diff.release());
3981 11 : ret = pLayerResult->CreateFeature(z.get());
3982 11 : if (ret != OGRERR_NONE)
3983 : {
3984 0 : if (!bSkipFailures)
3985 : {
3986 0 : goto done;
3987 : }
3988 : else
3989 : {
3990 0 : CPLErrorReset();
3991 0 : ret = OGRERR_NONE;
3992 : }
3993 : }
3994 : }
3995 : }
3996 :
3997 : // restore filter on method layer and add features based on it
3998 7 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3999 17 : for (auto &&x : pLayerMethod)
4000 : {
4001 :
4002 10 : if (pfnProgress)
4003 : {
4004 1 : double p = progress_counter / progress_max;
4005 1 : if (p > progress_ticker)
4006 : {
4007 1 : if (!pfnProgress(p, "", pProgressArg))
4008 : {
4009 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4010 0 : ret = OGRERR_FAILURE;
4011 0 : goto done;
4012 : }
4013 : }
4014 1 : progress_counter += 1.0;
4015 : }
4016 :
4017 : // set up the filter on input layer
4018 10 : CPLErrorReset();
4019 : OGRGeometry *x_geom =
4020 10 : set_filter_from(this, pGeometryInputFilter, x.get());
4021 10 : if (CPLGetLastErrorType() != CE_None)
4022 : {
4023 0 : if (!bSkipFailures)
4024 : {
4025 0 : ret = OGRERR_FAILURE;
4026 0 : goto done;
4027 : }
4028 : else
4029 : {
4030 0 : CPLErrorReset();
4031 0 : ret = OGRERR_NONE;
4032 : }
4033 : }
4034 10 : if (!x_geom)
4035 : {
4036 0 : continue;
4037 : }
4038 :
4039 : OGRGeometryUniquePtr x_geom_diff(
4040 : x_geom
4041 10 : ->clone()); // this will be the geometry of the result feature
4042 25 : for (auto &&y : this)
4043 : {
4044 15 : OGRGeometry *y_geom = y->GetGeometryRef();
4045 15 : if (!y_geom)
4046 : {
4047 0 : continue;
4048 : }
4049 :
4050 15 : if (x_geom_diff)
4051 : {
4052 15 : CPLErrorReset();
4053 : OGRGeometryUniquePtr x_geom_diff_new(
4054 15 : x_geom_diff->Difference(y_geom));
4055 30 : if (CPLGetLastErrorType() != CE_None ||
4056 15 : x_geom_diff_new == nullptr)
4057 : {
4058 0 : if (!bSkipFailures)
4059 : {
4060 0 : ret = OGRERR_FAILURE;
4061 0 : goto done;
4062 : }
4063 : else
4064 : {
4065 0 : CPLErrorReset();
4066 0 : ret = OGRERR_NONE;
4067 : }
4068 : }
4069 : else
4070 : {
4071 15 : x_geom_diff.swap(x_geom_diff_new);
4072 : }
4073 : }
4074 : }
4075 :
4076 10 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
4077 : {
4078 : // ok
4079 : }
4080 : else
4081 : {
4082 7 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4083 7 : z->SetFieldsFrom(x.get(), mapMethod);
4084 7 : if (bPromoteToMulti)
4085 1 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
4086 7 : z->SetGeometryDirectly(x_geom_diff.release());
4087 7 : ret = pLayerResult->CreateFeature(z.get());
4088 7 : if (ret != OGRERR_NONE)
4089 : {
4090 0 : if (!bSkipFailures)
4091 : {
4092 0 : goto done;
4093 : }
4094 : else
4095 : {
4096 0 : CPLErrorReset();
4097 0 : ret = OGRERR_NONE;
4098 : }
4099 : }
4100 : }
4101 : }
4102 7 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4103 : {
4104 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4105 0 : ret = OGRERR_FAILURE;
4106 0 : goto done;
4107 : }
4108 7 : done:
4109 : // release resources
4110 7 : SetSpatialFilter(pGeometryInputFilter);
4111 7 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4112 7 : if (pGeometryMethodFilter)
4113 0 : delete pGeometryMethodFilter;
4114 7 : if (pGeometryInputFilter)
4115 0 : delete pGeometryInputFilter;
4116 7 : if (mapInput)
4117 4 : VSIFree(mapInput);
4118 7 : if (mapMethod)
4119 3 : VSIFree(mapMethod);
4120 7 : return ret;
4121 : }
4122 :
4123 : /************************************************************************/
4124 : /* OGR_L_Union() */
4125 : /************************************************************************/
4126 :
4127 : /**
4128 : * \brief Union of two layers.
4129 : *
4130 : * The result layer contains features whose geometries represent areas
4131 : * that are in either in the input layer, in the method layer, or in
4132 : * both. The features in the result layer have attributes from both
4133 : * input and method layers. For features which represent areas that
4134 : * are only in the input or in the method layer the respective
4135 : * attributes have undefined values. The schema of the result layer
4136 : * can be set by the user or, if it is empty, is initialized to
4137 : * contain all fields in the input and method layers.
4138 : *
4139 : * \note If the schema of the result is set by user and contains
4140 : * fields that have the same name as a field in input and in method
4141 : * layer, then the attribute in the result feature will get the value
4142 : * from the feature of the method layer (even if it is undefined).
4143 : *
4144 : * \note For best performance use the minimum amount of features in
4145 : * the method layer and copy it into a memory layer.
4146 : *
4147 : * \note This method relies on GEOS support. Do not use unless the
4148 : * GEOS support is compiled in.
4149 : *
4150 : * The recognized list of options is :
4151 : * <ul>
4152 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4153 : * feature could not be inserted or a GEOS call failed.
4154 : * </li>
4155 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4156 : * into MultiPolygons, LineStrings to MultiLineStrings or
4157 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4158 : * </li>
4159 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4160 : * will be created from the fields of the input layer.
4161 : * </li>
4162 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4163 : * will be created from the fields of the method layer.
4164 : * </li>
4165 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
4166 : * geometries to pretest intersection of features of method layer
4167 : * with features of this layer.
4168 : * </li>
4169 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
4170 : * result features with lower dimension geometry that would
4171 : * otherwise be added to the result layer. The default is YES, to add
4172 : * features with lower dimension geometry, but only if the result layer
4173 : * has an unknown geometry type.
4174 : * </li>
4175 : * </ul>
4176 : *
4177 : * This function is the same as the C++ method OGRLayer::Union().
4178 : *
4179 : * @param pLayerInput the input layer. Should not be NULL.
4180 : *
4181 : * @param pLayerMethod the method layer. Should not be NULL.
4182 : *
4183 : * @param pLayerResult the layer where the features resulting from the
4184 : * operation are inserted. Should not be NULL. See above the note
4185 : * about the schema.
4186 : *
4187 : * @param papszOptions NULL terminated list of options (may be NULL).
4188 : *
4189 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4190 : * reporting progress or NULL.
4191 : *
4192 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4193 : *
4194 : * @return an error code if there was an error or the execution was
4195 : * interrupted, OGRERR_NONE otherwise.
4196 : *
4197 : * @note The first geometry field is always used.
4198 : *
4199 : * @since OGR 1.10
4200 : */
4201 :
4202 7 : OGRErr OGR_L_Union(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
4203 : OGRLayerH pLayerResult, char **papszOptions,
4204 : GDALProgressFunc pfnProgress, void *pProgressArg)
4205 :
4206 : {
4207 7 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE);
4208 7 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE);
4209 7 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE);
4210 :
4211 : return OGRLayer::FromHandle(pLayerInput)
4212 7 : ->Union(OGRLayer::FromHandle(pLayerMethod),
4213 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
4214 7 : pProgressArg);
4215 : }
4216 :
4217 : /************************************************************************/
4218 : /* SymDifference() */
4219 : /************************************************************************/
4220 :
4221 : /**
4222 : * \brief Symmetrical difference of two layers.
4223 : *
4224 : * The result layer contains features whose geometries represent areas
4225 : * that are in either in the input layer or in the method layer but
4226 : * not in both. The features in the result layer have attributes from
4227 : * both input and method layers. For features which represent areas
4228 : * that are only in the input or in the method layer the respective
4229 : * attributes have undefined values. The schema of the result layer
4230 : * can be set by the user or, if it is empty, is initialized to
4231 : * contain all fields in the input and method layers.
4232 : *
4233 : * \note If the schema of the result is set by user and contains
4234 : * fields that have the same name as a field in input and in method
4235 : * layer, then the attribute in the result feature will get the value
4236 : * from the feature of the method layer (even if it is undefined).
4237 : *
4238 : * \note For best performance use the minimum amount of features in
4239 : * the method layer and copy it into a memory layer.
4240 : *
4241 : * \note This method relies on GEOS support. Do not use unless the
4242 : * GEOS support is compiled in.
4243 : *
4244 : * The recognized list of options is :
4245 : * <ul>
4246 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4247 : * feature could not be inserted or a GEOS call failed.
4248 : * </li>
4249 : * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
4250 : * into MultiPolygons, or LineStrings to MultiLineStrings.
4251 : * </li>
4252 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4253 : * will be created from the fields of the input layer.
4254 : * </li>
4255 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4256 : * will be created from the fields of the method layer.
4257 : * </li>
4258 : * </ul>
4259 : *
4260 : * This method is the same as the C function OGR_L_SymDifference().
4261 : *
4262 : * @param pLayerMethod the method layer. Should not be NULL.
4263 : *
4264 : * @param pLayerResult the layer where the features resulting from the
4265 : * operation are inserted. Should not be NULL. See above the note
4266 : * about the schema.
4267 : *
4268 : * @param papszOptions NULL terminated list of options (may be NULL).
4269 : *
4270 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4271 : * reporting progress or NULL.
4272 : *
4273 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4274 : *
4275 : * @return an error code if there was an error or the execution was
4276 : * interrupted, OGRERR_NONE otherwise.
4277 : *
4278 : * @note The first geometry field is always used.
4279 : *
4280 : * @since OGR 1.10
4281 : */
4282 :
4283 4 : OGRErr OGRLayer::SymDifference(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
4284 : char **papszOptions,
4285 : GDALProgressFunc pfnProgress, void *pProgressArg)
4286 : {
4287 4 : OGRErr ret = OGRERR_NONE;
4288 4 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
4289 4 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
4290 4 : OGRFeatureDefn *poDefnResult = nullptr;
4291 4 : OGRGeometry *pGeometryMethodFilter = nullptr;
4292 4 : OGRGeometry *pGeometryInputFilter = nullptr;
4293 4 : int *mapInput = nullptr;
4294 4 : int *mapMethod = nullptr;
4295 : double progress_max =
4296 4 : static_cast<double>(GetFeatureCount(FALSE)) +
4297 4 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
4298 4 : double progress_counter = 0;
4299 4 : double progress_ticker = 0;
4300 : const bool bSkipFailures =
4301 4 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4302 4 : const bool bPromoteToMulti = CPLTestBool(
4303 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4304 :
4305 : // check for GEOS
4306 4 : if (!OGRGeometryFactory::haveGEOS())
4307 : {
4308 0 : CPLError(CE_Failure, CPLE_AppDefined,
4309 : "OGRLayer::SymDifference() requires GEOS support");
4310 0 : return OGRERR_UNSUPPORTED_OPERATION;
4311 : }
4312 :
4313 : // get resources
4314 4 : ret = clone_spatial_filter(this, &pGeometryInputFilter);
4315 4 : if (ret != OGRERR_NONE)
4316 0 : goto done;
4317 4 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4318 4 : if (ret != OGRERR_NONE)
4319 0 : goto done;
4320 4 : ret = create_field_map(poDefnInput, &mapInput);
4321 4 : if (ret != OGRERR_NONE)
4322 0 : goto done;
4323 4 : ret = create_field_map(poDefnMethod, &mapMethod);
4324 4 : if (ret != OGRERR_NONE)
4325 0 : goto done;
4326 4 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
4327 : mapMethod, true, papszOptions);
4328 4 : if (ret != OGRERR_NONE)
4329 0 : goto done;
4330 4 : poDefnResult = pLayerResult->GetLayerDefn();
4331 :
4332 : // add features based on input layer
4333 12 : for (auto &&x : this)
4334 : {
4335 :
4336 8 : if (pfnProgress)
4337 : {
4338 2 : double p = progress_counter / progress_max;
4339 2 : if (p > progress_ticker)
4340 : {
4341 1 : if (!pfnProgress(p, "", pProgressArg))
4342 : {
4343 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4344 0 : ret = OGRERR_FAILURE;
4345 0 : goto done;
4346 : }
4347 : }
4348 2 : progress_counter += 1.0;
4349 : }
4350 :
4351 : // set up the filter on method layer
4352 8 : CPLErrorReset();
4353 : OGRGeometry *x_geom =
4354 8 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
4355 8 : if (CPLGetLastErrorType() != CE_None)
4356 : {
4357 0 : if (!bSkipFailures)
4358 : {
4359 0 : ret = OGRERR_FAILURE;
4360 0 : goto done;
4361 : }
4362 : else
4363 : {
4364 0 : CPLErrorReset();
4365 0 : ret = OGRERR_NONE;
4366 : }
4367 : }
4368 8 : if (!x_geom)
4369 : {
4370 0 : continue;
4371 : }
4372 :
4373 : OGRGeometryUniquePtr geom(
4374 : x_geom
4375 8 : ->clone()); // this will be the geometry of the result feature
4376 15 : for (auto &&y : pLayerMethod)
4377 : {
4378 9 : OGRGeometry *y_geom = y->GetGeometryRef();
4379 9 : if (!y_geom)
4380 : {
4381 0 : continue;
4382 : }
4383 9 : if (geom)
4384 : {
4385 9 : CPLErrorReset();
4386 9 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
4387 9 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
4388 : {
4389 0 : if (!bSkipFailures)
4390 : {
4391 0 : ret = OGRERR_FAILURE;
4392 0 : goto done;
4393 : }
4394 : else
4395 : {
4396 0 : CPLErrorReset();
4397 0 : ret = OGRERR_NONE;
4398 : }
4399 : }
4400 : else
4401 : {
4402 9 : geom.swap(geom_new);
4403 : }
4404 : }
4405 9 : if (geom && geom->IsEmpty())
4406 2 : break;
4407 : }
4408 :
4409 8 : if (geom && !geom->IsEmpty())
4410 : {
4411 6 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4412 6 : z->SetFieldsFrom(x.get(), mapInput);
4413 6 : if (bPromoteToMulti)
4414 2 : geom.reset(promote_to_multi(geom.release()));
4415 6 : z->SetGeometryDirectly(geom.release());
4416 6 : ret = pLayerResult->CreateFeature(z.get());
4417 6 : if (ret != OGRERR_NONE)
4418 : {
4419 0 : if (!bSkipFailures)
4420 : {
4421 0 : goto done;
4422 : }
4423 : else
4424 : {
4425 0 : CPLErrorReset();
4426 0 : ret = OGRERR_NONE;
4427 : }
4428 : }
4429 : }
4430 : }
4431 :
4432 : // restore filter on method layer and add features based on it
4433 4 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4434 10 : for (auto &&x : pLayerMethod)
4435 : {
4436 :
4437 6 : if (pfnProgress)
4438 : {
4439 2 : double p = progress_counter / progress_max;
4440 2 : if (p > progress_ticker)
4441 : {
4442 2 : if (!pfnProgress(p, "", pProgressArg))
4443 : {
4444 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4445 0 : ret = OGRERR_FAILURE;
4446 0 : goto done;
4447 : }
4448 : }
4449 2 : progress_counter += 1.0;
4450 : }
4451 :
4452 : // set up the filter on input layer
4453 6 : CPLErrorReset();
4454 : OGRGeometry *x_geom =
4455 6 : set_filter_from(this, pGeometryInputFilter, x.get());
4456 6 : if (CPLGetLastErrorType() != CE_None)
4457 : {
4458 0 : if (!bSkipFailures)
4459 : {
4460 0 : ret = OGRERR_FAILURE;
4461 0 : goto done;
4462 : }
4463 : else
4464 : {
4465 0 : CPLErrorReset();
4466 0 : ret = OGRERR_NONE;
4467 : }
4468 : }
4469 6 : if (!x_geom)
4470 : {
4471 0 : continue;
4472 : }
4473 :
4474 : OGRGeometryUniquePtr geom(
4475 : x_geom
4476 6 : ->clone()); // this will be the geometry of the result feature
4477 13 : for (auto &&y : this)
4478 : {
4479 9 : OGRGeometry *y_geom = y->GetGeometryRef();
4480 9 : if (!y_geom)
4481 0 : continue;
4482 9 : if (geom)
4483 : {
4484 9 : CPLErrorReset();
4485 9 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
4486 9 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
4487 : {
4488 0 : if (!bSkipFailures)
4489 : {
4490 0 : ret = OGRERR_FAILURE;
4491 0 : goto done;
4492 : }
4493 : else
4494 : {
4495 0 : CPLErrorReset();
4496 0 : ret = OGRERR_NONE;
4497 : }
4498 : }
4499 : else
4500 : {
4501 9 : geom.swap(geom_new);
4502 : }
4503 : }
4504 9 : if (geom == nullptr || geom->IsEmpty())
4505 2 : break;
4506 : }
4507 :
4508 6 : if (geom && !geom->IsEmpty())
4509 : {
4510 4 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4511 4 : z->SetFieldsFrom(x.get(), mapMethod);
4512 4 : if (bPromoteToMulti)
4513 1 : geom.reset(promote_to_multi(geom.release()));
4514 4 : z->SetGeometryDirectly(geom.release());
4515 4 : ret = pLayerResult->CreateFeature(z.get());
4516 4 : if (ret != OGRERR_NONE)
4517 : {
4518 0 : if (!bSkipFailures)
4519 : {
4520 0 : goto done;
4521 : }
4522 : else
4523 : {
4524 0 : CPLErrorReset();
4525 0 : ret = OGRERR_NONE;
4526 : }
4527 : }
4528 : }
4529 : }
4530 4 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4531 : {
4532 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4533 0 : ret = OGRERR_FAILURE;
4534 0 : goto done;
4535 : }
4536 4 : done:
4537 : // release resources
4538 4 : SetSpatialFilter(pGeometryInputFilter);
4539 4 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4540 4 : if (pGeometryMethodFilter)
4541 0 : delete pGeometryMethodFilter;
4542 4 : if (pGeometryInputFilter)
4543 0 : delete pGeometryInputFilter;
4544 4 : if (mapInput)
4545 3 : VSIFree(mapInput);
4546 4 : if (mapMethod)
4547 3 : VSIFree(mapMethod);
4548 4 : return ret;
4549 : }
4550 :
4551 : /************************************************************************/
4552 : /* OGR_L_SymDifference() */
4553 : /************************************************************************/
4554 :
4555 : /**
4556 : * \brief Symmetrical difference of two layers.
4557 : *
4558 : * The result layer contains features whose geometries represent areas
4559 : * that are in either in the input layer or in the method layer but
4560 : * not in both. The features in the result layer have attributes from
4561 : * both input and method layers. For features which represent areas
4562 : * that are only in the input or in the method layer the respective
4563 : * attributes have undefined values. The schema of the result layer
4564 : * can be set by the user or, if it is empty, is initialized to
4565 : * contain all fields in the input and method layers.
4566 : *
4567 : * \note If the schema of the result is set by user and contains
4568 : * fields that have the same name as a field in input and in method
4569 : * layer, then the attribute in the result feature will get the value
4570 : * from the feature of the method layer (even if it is undefined).
4571 : *
4572 : * \note For best performance use the minimum amount of features in
4573 : * the method layer and copy it into a memory layer.
4574 : *
4575 : * \note This method relies on GEOS support. Do not use unless the
4576 : * GEOS support is compiled in.
4577 : *
4578 : * The recognized list of options is :
4579 : * <ul>
4580 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4581 : * feature could not be inserted or a GEOS call failed.
4582 : * </li>
4583 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4584 : * into MultiPolygons, LineStrings to MultiLineStrings or
4585 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4586 : * </li>
4587 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4588 : * will be created from the fields of the input layer.
4589 : * </li>
4590 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4591 : * will be created from the fields of the method layer.
4592 : * </li>
4593 : * </ul>
4594 : *
4595 : * This function is the same as the C++ method OGRLayer::SymDifference().
4596 : *
4597 : * @param pLayerInput the input layer. Should not be NULL.
4598 : *
4599 : * @param pLayerMethod the method layer. Should not be NULL.
4600 : *
4601 : * @param pLayerResult the layer where the features resulting from the
4602 : * operation are inserted. Should not be NULL. See above the note
4603 : * about the schema.
4604 : *
4605 : * @param papszOptions NULL terminated list of options (may be NULL).
4606 : *
4607 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4608 : * reporting progress or NULL.
4609 : *
4610 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4611 : *
4612 : * @return an error code if there was an error or the execution was
4613 : * interrupted, OGRERR_NONE otherwise.
4614 : *
4615 : * @note The first geometry field is always used.
4616 : *
4617 : * @since OGR 1.10
4618 : */
4619 :
4620 4 : OGRErr OGR_L_SymDifference(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
4621 : OGRLayerH pLayerResult, char **papszOptions,
4622 : GDALProgressFunc pfnProgress, void *pProgressArg)
4623 :
4624 : {
4625 4 : VALIDATE_POINTER1(pLayerInput, "OGR_L_SymDifference",
4626 : OGRERR_INVALID_HANDLE);
4627 4 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_SymDifference",
4628 : OGRERR_INVALID_HANDLE);
4629 4 : VALIDATE_POINTER1(pLayerResult, "OGR_L_SymDifference",
4630 : OGRERR_INVALID_HANDLE);
4631 :
4632 : return OGRLayer::FromHandle(pLayerInput)
4633 4 : ->SymDifference(OGRLayer::FromHandle(pLayerMethod),
4634 : OGRLayer::FromHandle(pLayerResult), papszOptions,
4635 4 : pfnProgress, pProgressArg);
4636 : }
4637 :
4638 : /************************************************************************/
4639 : /* Identity() */
4640 : /************************************************************************/
4641 :
4642 : /**
4643 : * \brief Identify the features of this layer with the ones from the
4644 : * identity layer.
4645 : *
4646 : * The result layer contains features whose geometries represent areas
4647 : * that are in the input layer. The features in the result layer have
4648 : * attributes from both input and method layers. The schema of the
4649 : * result layer can be set by the user or, if it is empty, is
4650 : * initialized to contain all fields in input and method layers.
4651 : *
4652 : * \note If the schema of the result is set by user and contains
4653 : * fields that have the same name as a field in input and in method
4654 : * layer, then the attribute in the result feature will get the value
4655 : * from the feature of the method layer (even if it is undefined).
4656 : *
4657 : * \note For best performance use the minimum amount of features in
4658 : * the method layer and copy it into a memory layer.
4659 : *
4660 : * \note This method relies on GEOS support. Do not use unless the
4661 : * GEOS support is compiled in.
4662 : *
4663 : * The recognized list of options is :
4664 : * <ul>
4665 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4666 : * feature could not be inserted or a GEOS call failed.
4667 : * </li>
4668 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4669 : * into MultiPolygons, LineStrings to MultiLineStrings or
4670 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4671 : * </li>
4672 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4673 : * will be created from the fields of the input layer.
4674 : * </li>
4675 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4676 : * will be created from the fields of the method layer.
4677 : * </li>
4678 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
4679 : * geometries to pretest intersection of features of method layer
4680 : * with features of this layer.
4681 : * </li>
4682 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
4683 : * result features with lower dimension geometry that would
4684 : * otherwise be added to the result layer. The default is YES, to add
4685 : * features with lower dimension geometry, but only if the result layer
4686 : * has an unknown geometry type.
4687 : * </li>
4688 : * </ul>
4689 : *
4690 : * This method is the same as the C function OGR_L_Identity().
4691 : *
4692 : * @param pLayerMethod the method layer. Should not be NULL.
4693 : *
4694 : * @param pLayerResult the layer where the features resulting from the
4695 : * operation are inserted. Should not be NULL. See above the note
4696 : * about the schema.
4697 : *
4698 : * @param papszOptions NULL terminated list of options (may be NULL).
4699 : *
4700 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4701 : * reporting progress or NULL.
4702 : *
4703 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4704 : *
4705 : * @return an error code if there was an error or the execution was
4706 : * interrupted, OGRERR_NONE otherwise.
4707 : *
4708 : * @note The first geometry field is always used.
4709 : *
4710 : * @since OGR 1.10
4711 : */
4712 :
4713 6 : OGRErr OGRLayer::Identity(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
4714 : char **papszOptions, GDALProgressFunc pfnProgress,
4715 : void *pProgressArg)
4716 : {
4717 6 : OGRErr ret = OGRERR_NONE;
4718 6 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
4719 6 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
4720 6 : OGRFeatureDefn *poDefnResult = nullptr;
4721 6 : OGRGeometry *pGeometryMethodFilter = nullptr;
4722 6 : int *mapInput = nullptr;
4723 6 : int *mapMethod = nullptr;
4724 6 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
4725 6 : double progress_counter = 0;
4726 6 : double progress_ticker = 0;
4727 : const bool bSkipFailures =
4728 6 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4729 6 : const bool bPromoteToMulti = CPLTestBool(
4730 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4731 6 : const bool bUsePreparedGeometries = CPLTestBool(
4732 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
4733 6 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
4734 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
4735 :
4736 : // check for GEOS
4737 6 : if (!OGRGeometryFactory::haveGEOS())
4738 : {
4739 0 : CPLError(CE_Failure, CPLE_AppDefined,
4740 : "OGRLayer::Identity() requires GEOS support");
4741 0 : return OGRERR_UNSUPPORTED_OPERATION;
4742 : }
4743 6 : if (bKeepLowerDimGeom)
4744 : {
4745 : // require that the result layer is of geom type unknown
4746 4 : if (pLayerResult->GetGeomType() != wkbUnknown)
4747 : {
4748 0 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
4749 : "since the result layer does not allow it.");
4750 0 : bKeepLowerDimGeom = FALSE;
4751 : }
4752 : }
4753 :
4754 : // get resources
4755 6 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4756 6 : if (ret != OGRERR_NONE)
4757 0 : goto done;
4758 6 : ret = create_field_map(poDefnInput, &mapInput);
4759 6 : if (ret != OGRERR_NONE)
4760 0 : goto done;
4761 6 : ret = create_field_map(poDefnMethod, &mapMethod);
4762 6 : if (ret != OGRERR_NONE)
4763 0 : goto done;
4764 6 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
4765 : mapMethod, true, papszOptions);
4766 6 : if (ret != OGRERR_NONE)
4767 0 : goto done;
4768 6 : poDefnResult = pLayerResult->GetLayerDefn();
4769 :
4770 : // split the features in input layer to the result layer
4771 18 : for (auto &&x : this)
4772 : {
4773 :
4774 12 : if (pfnProgress)
4775 : {
4776 2 : double p = progress_counter / progress_max;
4777 2 : if (p > progress_ticker)
4778 : {
4779 1 : if (!pfnProgress(p, "", pProgressArg))
4780 : {
4781 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4782 0 : ret = OGRERR_FAILURE;
4783 0 : goto done;
4784 : }
4785 : }
4786 2 : progress_counter += 1.0;
4787 : }
4788 :
4789 : // set up the filter on method layer
4790 12 : CPLErrorReset();
4791 : OGRGeometry *x_geom =
4792 12 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
4793 12 : if (CPLGetLastErrorType() != CE_None)
4794 : {
4795 0 : if (!bSkipFailures)
4796 : {
4797 0 : ret = OGRERR_FAILURE;
4798 0 : goto done;
4799 : }
4800 : else
4801 : {
4802 0 : CPLErrorReset();
4803 0 : ret = OGRERR_NONE;
4804 : }
4805 : }
4806 12 : if (!x_geom)
4807 : {
4808 0 : continue;
4809 : }
4810 :
4811 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
4812 12 : if (bUsePreparedGeometries)
4813 : {
4814 12 : x_prepared_geom.reset(
4815 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
4816 12 : if (!x_prepared_geom)
4817 : {
4818 0 : goto done;
4819 : }
4820 : }
4821 :
4822 : OGRGeometryUniquePtr x_geom_diff(
4823 : x_geom
4824 12 : ->clone()); // this will be the geometry of the result feature
4825 26 : for (auto &&y : pLayerMethod)
4826 : {
4827 14 : OGRGeometry *y_geom = y->GetGeometryRef();
4828 14 : if (!y_geom)
4829 0 : continue;
4830 :
4831 14 : CPLErrorReset();
4832 28 : if (x_prepared_geom &&
4833 14 : !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
4834 14 : OGRGeometry::ToHandle(y_geom))))
4835 : {
4836 0 : if (CPLGetLastErrorType() == CE_None)
4837 : {
4838 0 : continue;
4839 : }
4840 : }
4841 14 : if (CPLGetLastErrorType() != CE_None)
4842 : {
4843 0 : if (!bSkipFailures)
4844 : {
4845 0 : ret = OGRERR_FAILURE;
4846 0 : goto done;
4847 : }
4848 : else
4849 : {
4850 0 : CPLErrorReset();
4851 0 : ret = OGRERR_NONE;
4852 : }
4853 : }
4854 :
4855 14 : CPLErrorReset();
4856 14 : OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
4857 14 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
4858 : {
4859 0 : if (!bSkipFailures)
4860 : {
4861 0 : ret = OGRERR_FAILURE;
4862 0 : goto done;
4863 : }
4864 : else
4865 : {
4866 0 : CPLErrorReset();
4867 0 : ret = OGRERR_NONE;
4868 : }
4869 : }
4870 28 : else if (poIntersection->IsEmpty() ||
4871 14 : (!bKeepLowerDimGeom &&
4872 6 : (x_geom->getDimension() == y_geom->getDimension() &&
4873 6 : poIntersection->getDimension() <
4874 6 : x_geom->getDimension())))
4875 : {
4876 : /* ok*/
4877 : }
4878 : else
4879 : {
4880 10 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4881 10 : z->SetFieldsFrom(x.get(), mapInput);
4882 10 : z->SetFieldsFrom(y.get(), mapMethod);
4883 10 : if (bPromoteToMulti)
4884 2 : poIntersection.reset(
4885 : promote_to_multi(poIntersection.release()));
4886 10 : z->SetGeometryDirectly(poIntersection.release());
4887 10 : if (x_geom_diff)
4888 : {
4889 10 : CPLErrorReset();
4890 : OGRGeometryUniquePtr x_geom_diff_new(
4891 10 : x_geom_diff->Difference(y_geom));
4892 20 : if (CPLGetLastErrorType() != CE_None ||
4893 10 : x_geom_diff_new == nullptr)
4894 : {
4895 0 : if (!bSkipFailures)
4896 : {
4897 0 : ret = OGRERR_FAILURE;
4898 0 : goto done;
4899 : }
4900 : else
4901 : {
4902 0 : CPLErrorReset();
4903 : }
4904 : }
4905 : else
4906 : {
4907 10 : x_geom_diff.swap(x_geom_diff_new);
4908 : }
4909 : }
4910 10 : ret = pLayerResult->CreateFeature(z.get());
4911 10 : if (ret != OGRERR_NONE)
4912 : {
4913 0 : if (!bSkipFailures)
4914 : {
4915 0 : goto done;
4916 : }
4917 : else
4918 : {
4919 0 : CPLErrorReset();
4920 0 : ret = OGRERR_NONE;
4921 : }
4922 : }
4923 : }
4924 : }
4925 :
4926 12 : x_prepared_geom.reset();
4927 :
4928 12 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
4929 : {
4930 : /* ok */
4931 : }
4932 : else
4933 : {
4934 10 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4935 10 : z->SetFieldsFrom(x.get(), mapInput);
4936 10 : if (bPromoteToMulti)
4937 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
4938 10 : z->SetGeometryDirectly(x_geom_diff.release());
4939 10 : ret = pLayerResult->CreateFeature(z.get());
4940 10 : if (ret != OGRERR_NONE)
4941 : {
4942 0 : if (!bSkipFailures)
4943 : {
4944 0 : goto done;
4945 : }
4946 : else
4947 : {
4948 0 : CPLErrorReset();
4949 0 : ret = OGRERR_NONE;
4950 : }
4951 : }
4952 : }
4953 : }
4954 6 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4955 : {
4956 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4957 0 : ret = OGRERR_FAILURE;
4958 0 : goto done;
4959 : }
4960 6 : done:
4961 : // release resources
4962 6 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4963 6 : if (pGeometryMethodFilter)
4964 0 : delete pGeometryMethodFilter;
4965 6 : if (mapInput)
4966 3 : VSIFree(mapInput);
4967 6 : if (mapMethod)
4968 3 : VSIFree(mapMethod);
4969 6 : return ret;
4970 : }
4971 :
4972 : /************************************************************************/
4973 : /* OGR_L_Identity() */
4974 : /************************************************************************/
4975 :
4976 : /**
4977 : * \brief Identify the features of this layer with the ones from the
4978 : * identity layer.
4979 : *
4980 : * The result layer contains features whose geometries represent areas
4981 : * that are in the input layer. The features in the result layer have
4982 : * attributes from both input and method layers. The schema of the
4983 : * result layer can be set by the user or, if it is empty, is
4984 : * initialized to contain all fields in input and method layers.
4985 : *
4986 : * \note If the schema of the result is set by user and contains
4987 : * fields that have the same name as a field in input and in method
4988 : * layer, then the attribute in the result feature will get the value
4989 : * from the feature of the method layer (even if it is undefined).
4990 : *
4991 : * \note For best performance use the minimum amount of features in
4992 : * the method layer and copy it into a memory layer.
4993 : *
4994 : * \note This method relies on GEOS support. Do not use unless the
4995 : * GEOS support is compiled in.
4996 : *
4997 : * The recognized list of options is :
4998 : * <ul>
4999 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5000 : * feature could not be inserted or a GEOS call failed.
5001 : * </li>
5002 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5003 : * into MultiPolygons, LineStrings to MultiLineStrings or
5004 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5005 : * </li>
5006 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5007 : * will be created from the fields of the input layer.
5008 : * </li>
5009 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5010 : * will be created from the fields of the method layer.
5011 : * </li>
5012 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
5013 : * geometries to pretest intersection of features of method layer
5014 : * with features of this layer.
5015 : * </li>
5016 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
5017 : * result features with lower dimension geometry that would
5018 : * otherwise be added to the result layer. The default is YES, to add
5019 : * features with lower dimension geometry, but only if the result layer
5020 : * has an unknown geometry type.
5021 : * </li>
5022 : * </ul>
5023 : *
5024 : * This function is the same as the C++ method OGRLayer::Identity().
5025 : *
5026 : * @param pLayerInput the input layer. Should not be NULL.
5027 : *
5028 : * @param pLayerMethod the method layer. Should not be NULL.
5029 : *
5030 : * @param pLayerResult the layer where the features resulting from the
5031 : * operation are inserted. Should not be NULL. See above the note
5032 : * about the schema.
5033 : *
5034 : * @param papszOptions NULL terminated list of options (may be NULL).
5035 : *
5036 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5037 : * reporting progress or NULL.
5038 : *
5039 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5040 : *
5041 : * @return an error code if there was an error or the execution was
5042 : * interrupted, OGRERR_NONE otherwise.
5043 : *
5044 : * @note The first geometry field is always used.
5045 : *
5046 : * @since OGR 1.10
5047 : */
5048 :
5049 6 : OGRErr OGR_L_Identity(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5050 : OGRLayerH pLayerResult, char **papszOptions,
5051 : GDALProgressFunc pfnProgress, void *pProgressArg)
5052 :
5053 : {
5054 6 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
5055 6 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
5056 6 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
5057 :
5058 : return OGRLayer::FromHandle(pLayerInput)
5059 6 : ->Identity(OGRLayer::FromHandle(pLayerMethod),
5060 : OGRLayer::FromHandle(pLayerResult), papszOptions,
5061 6 : pfnProgress, pProgressArg);
5062 : }
5063 :
5064 : /************************************************************************/
5065 : /* Update() */
5066 : /************************************************************************/
5067 :
5068 : /**
5069 : * \brief Update this layer with features from the update layer.
5070 : *
5071 : * The result layer contains features whose geometries represent areas
5072 : * that are either in the input layer or in the method layer. The
5073 : * features in the result layer have areas of the features of the
5074 : * method layer or those ares of the features of the input layer that
5075 : * are not covered by the method layer. The features of the result
5076 : * layer get their attributes from the input layer. The schema of the
5077 : * result layer can be set by the user or, if it is empty, is
5078 : * initialized to contain all fields in the input layer.
5079 : *
5080 : * \note If the schema of the result is set by user and contains
5081 : * fields that have the same name as a field in the method layer, then
5082 : * the attribute in the result feature the originates from the method
5083 : * layer will get the value from the feature of the method layer.
5084 : *
5085 : * \note For best performance use the minimum amount of features in
5086 : * the method layer and copy it into a memory layer.
5087 : *
5088 : * \note This method relies on GEOS support. Do not use unless the
5089 : * GEOS support is compiled in.
5090 : *
5091 : * The recognized list of options is :
5092 : * <ul>
5093 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5094 : * feature could not be inserted or a GEOS call failed.
5095 : * </li>
5096 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5097 : * into MultiPolygons, LineStrings to MultiLineStrings or
5098 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5099 : * </li>
5100 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5101 : * will be created from the fields of the input layer.
5102 : * </li>
5103 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5104 : * will be created from the fields of the method layer.
5105 : * </li>
5106 : * </ul>
5107 : *
5108 : * This method is the same as the C function OGR_L_Update().
5109 : *
5110 : * @param pLayerMethod the method layer. Should not be NULL.
5111 : *
5112 : * @param pLayerResult the layer where the features resulting from the
5113 : * operation are inserted. Should not be NULL. See above the note
5114 : * about the schema.
5115 : *
5116 : * @param papszOptions NULL terminated list of options (may be NULL).
5117 : *
5118 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5119 : * reporting progress or NULL.
5120 : *
5121 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5122 : *
5123 : * @return an error code if there was an error or the execution was
5124 : * interrupted, OGRERR_NONE otherwise.
5125 : *
5126 : * @note The first geometry field is always used.
5127 : *
5128 : * @since OGR 1.10
5129 : */
5130 :
5131 5 : OGRErr OGRLayer::Update(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5132 : char **papszOptions, GDALProgressFunc pfnProgress,
5133 : void *pProgressArg)
5134 : {
5135 5 : OGRErr ret = OGRERR_NONE;
5136 5 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
5137 5 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
5138 5 : OGRFeatureDefn *poDefnResult = nullptr;
5139 5 : OGRGeometry *pGeometryMethodFilter = nullptr;
5140 5 : int *mapInput = nullptr;
5141 5 : int *mapMethod = nullptr;
5142 : double progress_max =
5143 5 : static_cast<double>(GetFeatureCount(FALSE)) +
5144 5 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
5145 5 : double progress_counter = 0;
5146 5 : double progress_ticker = 0;
5147 : const bool bSkipFailures =
5148 5 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5149 5 : const bool bPromoteToMulti = CPLTestBool(
5150 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5151 :
5152 : // check for GEOS
5153 5 : if (!OGRGeometryFactory::haveGEOS())
5154 : {
5155 0 : CPLError(CE_Failure, CPLE_AppDefined,
5156 : "OGRLayer::Update() requires GEOS support");
5157 0 : return OGRERR_UNSUPPORTED_OPERATION;
5158 : }
5159 :
5160 : // get resources
5161 5 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5162 5 : if (ret != OGRERR_NONE)
5163 0 : goto done;
5164 5 : ret = create_field_map(poDefnInput, &mapInput);
5165 5 : if (ret != OGRERR_NONE)
5166 0 : goto done;
5167 5 : ret = create_field_map(poDefnMethod, &mapMethod);
5168 5 : if (ret != OGRERR_NONE)
5169 0 : goto done;
5170 5 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
5171 : mapMethod, false, papszOptions);
5172 5 : if (ret != OGRERR_NONE)
5173 0 : goto done;
5174 5 : poDefnResult = pLayerResult->GetLayerDefn();
5175 :
5176 : // add clipped features from the input layer
5177 15 : for (auto &&x : this)
5178 : {
5179 :
5180 10 : if (pfnProgress)
5181 : {
5182 2 : double p = progress_counter / progress_max;
5183 2 : if (p > progress_ticker)
5184 : {
5185 1 : if (!pfnProgress(p, "", pProgressArg))
5186 : {
5187 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5188 0 : ret = OGRERR_FAILURE;
5189 0 : goto done;
5190 : }
5191 : }
5192 2 : progress_counter += 1.0;
5193 : }
5194 :
5195 : // set up the filter on method layer
5196 10 : CPLErrorReset();
5197 : OGRGeometry *x_geom =
5198 10 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5199 10 : if (CPLGetLastErrorType() != CE_None)
5200 : {
5201 0 : if (!bSkipFailures)
5202 : {
5203 0 : ret = OGRERR_FAILURE;
5204 0 : goto done;
5205 : }
5206 : else
5207 : {
5208 0 : CPLErrorReset();
5209 0 : ret = OGRERR_NONE;
5210 : }
5211 : }
5212 10 : if (!x_geom)
5213 : {
5214 0 : continue;
5215 : }
5216 :
5217 : OGRGeometryUniquePtr x_geom_diff(
5218 10 : x_geom->clone()); // this will be the geometry of a result feature
5219 24 : for (auto &&y : pLayerMethod)
5220 : {
5221 14 : OGRGeometry *y_geom = y->GetGeometryRef();
5222 14 : if (!y_geom)
5223 0 : continue;
5224 14 : if (x_geom_diff)
5225 : {
5226 14 : CPLErrorReset();
5227 : OGRGeometryUniquePtr x_geom_diff_new(
5228 14 : x_geom_diff->Difference(y_geom));
5229 28 : if (CPLGetLastErrorType() != CE_None ||
5230 14 : x_geom_diff_new == nullptr)
5231 : {
5232 0 : if (!bSkipFailures)
5233 : {
5234 0 : ret = OGRERR_FAILURE;
5235 0 : goto done;
5236 : }
5237 : else
5238 : {
5239 0 : CPLErrorReset();
5240 0 : ret = OGRERR_NONE;
5241 : }
5242 : }
5243 : else
5244 : {
5245 14 : x_geom_diff.swap(x_geom_diff_new);
5246 : }
5247 : }
5248 : }
5249 :
5250 10 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
5251 : {
5252 : /* ok */
5253 : }
5254 : else
5255 : {
5256 6 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5257 6 : z->SetFieldsFrom(x.get(), mapInput);
5258 6 : if (bPromoteToMulti)
5259 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
5260 6 : z->SetGeometryDirectly(x_geom_diff.release());
5261 6 : ret = pLayerResult->CreateFeature(z.get());
5262 6 : if (ret != OGRERR_NONE)
5263 : {
5264 0 : if (!bSkipFailures)
5265 : {
5266 0 : goto done;
5267 : }
5268 : else
5269 : {
5270 0 : CPLErrorReset();
5271 0 : ret = OGRERR_NONE;
5272 : }
5273 : }
5274 : }
5275 : }
5276 :
5277 : // restore the original filter and add features from the update layer
5278 5 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5279 12 : for (auto &&y : pLayerMethod)
5280 : {
5281 :
5282 7 : if (pfnProgress)
5283 : {
5284 1 : double p = progress_counter / progress_max;
5285 1 : if (p > progress_ticker)
5286 : {
5287 1 : if (!pfnProgress(p, "", pProgressArg))
5288 : {
5289 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5290 0 : ret = OGRERR_FAILURE;
5291 0 : goto done;
5292 : }
5293 : }
5294 1 : progress_counter += 1.0;
5295 : }
5296 :
5297 7 : OGRGeometry *y_geom = y->StealGeometry();
5298 7 : if (!y_geom)
5299 0 : continue;
5300 7 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5301 7 : if (mapMethod)
5302 3 : z->SetFieldsFrom(y.get(), mapMethod);
5303 7 : z->SetGeometryDirectly(y_geom);
5304 7 : ret = pLayerResult->CreateFeature(z.get());
5305 7 : if (ret != OGRERR_NONE)
5306 : {
5307 0 : if (!bSkipFailures)
5308 : {
5309 0 : goto done;
5310 : }
5311 : else
5312 : {
5313 0 : CPLErrorReset();
5314 0 : ret = OGRERR_NONE;
5315 : }
5316 : }
5317 : }
5318 5 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5319 : {
5320 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5321 0 : ret = OGRERR_FAILURE;
5322 0 : goto done;
5323 : }
5324 5 : done:
5325 : // release resources
5326 5 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5327 5 : if (pGeometryMethodFilter)
5328 0 : delete pGeometryMethodFilter;
5329 5 : if (mapInput)
5330 3 : VSIFree(mapInput);
5331 5 : if (mapMethod)
5332 3 : VSIFree(mapMethod);
5333 5 : return ret;
5334 : }
5335 :
5336 : /************************************************************************/
5337 : /* OGR_L_Update() */
5338 : /************************************************************************/
5339 :
5340 : /**
5341 : * \brief Update this layer with features from the update layer.
5342 : *
5343 : * The result layer contains features whose geometries represent areas
5344 : * that are either in the input layer or in the method layer. The
5345 : * features in the result layer have areas of the features of the
5346 : * method layer or those ares of the features of the input layer that
5347 : * are not covered by the method layer. The features of the result
5348 : * layer get their attributes from the input layer. The schema of the
5349 : * result layer can be set by the user or, if it is empty, is
5350 : * initialized to contain all fields in the input layer.
5351 : *
5352 : * \note If the schema of the result is set by user and contains
5353 : * fields that have the same name as a field in the method layer, then
5354 : * the attribute in the result feature the originates from the method
5355 : * layer will get the value from the feature of the method layer.
5356 : *
5357 : * \note For best performance use the minimum amount of features in
5358 : * the method layer and copy it into a memory layer.
5359 : *
5360 : * \note This method relies on GEOS support. Do not use unless the
5361 : * GEOS support is compiled in.
5362 : *
5363 : * The recognized list of options is :
5364 : * <ul>
5365 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5366 : * feature could not be inserted or a GEOS call failed.
5367 : * </li>
5368 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5369 : * into MultiPolygons, LineStrings to MultiLineStrings or
5370 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5371 : * </li>
5372 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5373 : * will be created from the fields of the input layer.
5374 : * </li>
5375 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5376 : * will be created from the fields of the method layer.
5377 : * </li>
5378 : * </ul>
5379 : *
5380 : * This function is the same as the C++ method OGRLayer::Update().
5381 : *
5382 : * @param pLayerInput the input layer. Should not be NULL.
5383 : *
5384 : * @param pLayerMethod the method layer. Should not be NULL.
5385 : *
5386 : * @param pLayerResult the layer where the features resulting from the
5387 : * operation are inserted. Should not be NULL. See above the note
5388 : * about the schema.
5389 : *
5390 : * @param papszOptions NULL terminated list of options (may be NULL).
5391 : *
5392 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5393 : * reporting progress or NULL.
5394 : *
5395 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5396 : *
5397 : * @return an error code if there was an error or the execution was
5398 : * interrupted, OGRERR_NONE otherwise.
5399 : *
5400 : * @note The first geometry field is always used.
5401 : *
5402 : * @since OGR 1.10
5403 : */
5404 :
5405 5 : OGRErr OGR_L_Update(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5406 : OGRLayerH pLayerResult, char **papszOptions,
5407 : GDALProgressFunc pfnProgress, void *pProgressArg)
5408 :
5409 : {
5410 5 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE);
5411 5 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE);
5412 5 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE);
5413 :
5414 : return OGRLayer::FromHandle(pLayerInput)
5415 5 : ->Update(OGRLayer::FromHandle(pLayerMethod),
5416 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
5417 5 : pProgressArg);
5418 : }
5419 :
5420 : /************************************************************************/
5421 : /* Clip() */
5422 : /************************************************************************/
5423 :
5424 : /**
5425 : * \brief Clip off areas that are not covered by the method layer.
5426 : *
5427 : * The result layer contains features whose geometries represent areas
5428 : * that are in the input layer and in the method layer. The features
5429 : * in the result layer have the (possibly clipped) areas of features
5430 : * in the input layer and the attributes from the same features. The
5431 : * schema of the result layer can be set by the user or, if it is
5432 : * empty, is initialized to contain all fields in the input layer.
5433 : *
5434 : * \note For best performance use the minimum amount of features in
5435 : * the method layer and copy it into a memory layer.
5436 : *
5437 : * \note This method relies on GEOS support. Do not use unless the
5438 : * GEOS support is compiled in.
5439 : *
5440 : * The recognized list of options is :
5441 : * <ul>
5442 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5443 : * feature could not be inserted or a GEOS call failed.
5444 : * </li>
5445 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5446 : * into MultiPolygons, LineStrings to MultiLineStrings or
5447 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5448 : * </li>
5449 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5450 : * will be created from the fields of the input layer.
5451 : * </li>
5452 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5453 : * will be created from the fields of the method layer.
5454 : * </li>
5455 : * </ul>
5456 : *
5457 : * This method is the same as the C function OGR_L_Clip().
5458 : *
5459 : * @param pLayerMethod the method layer. Should not be NULL.
5460 : *
5461 : * @param pLayerResult the layer where the features resulting from the
5462 : * operation are inserted. Should not be NULL. See above the note
5463 : * about the schema.
5464 : *
5465 : * @param papszOptions NULL terminated list of options (may be NULL).
5466 : *
5467 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5468 : * reporting progress or NULL.
5469 : *
5470 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5471 : *
5472 : * @return an error code if there was an error or the execution was
5473 : * interrupted, OGRERR_NONE otherwise.
5474 : *
5475 : * @note The first geometry field is always used.
5476 : *
5477 : * @since OGR 1.10
5478 : */
5479 :
5480 3 : OGRErr OGRLayer::Clip(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5481 : char **papszOptions, GDALProgressFunc pfnProgress,
5482 : void *pProgressArg)
5483 : {
5484 3 : OGRErr ret = OGRERR_NONE;
5485 3 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
5486 3 : OGRFeatureDefn *poDefnResult = nullptr;
5487 3 : OGRGeometry *pGeometryMethodFilter = nullptr;
5488 3 : int *mapInput = nullptr;
5489 3 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
5490 3 : double progress_counter = 0;
5491 3 : double progress_ticker = 0;
5492 : const bool bSkipFailures =
5493 3 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5494 3 : const bool bPromoteToMulti = CPLTestBool(
5495 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5496 :
5497 : // check for GEOS
5498 3 : if (!OGRGeometryFactory::haveGEOS())
5499 : {
5500 0 : CPLError(CE_Failure, CPLE_AppDefined,
5501 : "OGRLayer::Clip() requires GEOS support");
5502 0 : return OGRERR_UNSUPPORTED_OPERATION;
5503 : }
5504 :
5505 3 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5506 3 : if (ret != OGRERR_NONE)
5507 0 : goto done;
5508 3 : ret = create_field_map(poDefnInput, &mapInput);
5509 3 : if (ret != OGRERR_NONE)
5510 0 : goto done;
5511 3 : ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
5512 : nullptr, false, papszOptions);
5513 3 : if (ret != OGRERR_NONE)
5514 0 : goto done;
5515 :
5516 3 : poDefnResult = pLayerResult->GetLayerDefn();
5517 9 : for (auto &&x : this)
5518 : {
5519 :
5520 6 : if (pfnProgress)
5521 : {
5522 2 : double p = progress_counter / progress_max;
5523 2 : if (p > progress_ticker)
5524 : {
5525 1 : if (!pfnProgress(p, "", pProgressArg))
5526 : {
5527 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5528 0 : ret = OGRERR_FAILURE;
5529 0 : goto done;
5530 : }
5531 : }
5532 2 : progress_counter += 1.0;
5533 : }
5534 :
5535 : // set up the filter on method layer
5536 6 : CPLErrorReset();
5537 : OGRGeometry *x_geom =
5538 6 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5539 6 : if (CPLGetLastErrorType() != CE_None)
5540 : {
5541 0 : if (!bSkipFailures)
5542 : {
5543 0 : ret = OGRERR_FAILURE;
5544 0 : goto done;
5545 : }
5546 : else
5547 : {
5548 0 : CPLErrorReset();
5549 0 : ret = OGRERR_NONE;
5550 : }
5551 : }
5552 6 : if (!x_geom)
5553 : {
5554 0 : continue;
5555 : }
5556 :
5557 : OGRGeometryUniquePtr
5558 0 : geom; // this will be the geometry of the result feature
5559 : // incrementally add area from y to geom
5560 12 : for (auto &&y : pLayerMethod)
5561 : {
5562 6 : OGRGeometry *y_geom = y->GetGeometryRef();
5563 6 : if (!y_geom)
5564 0 : continue;
5565 6 : if (!geom)
5566 : {
5567 6 : geom.reset(y_geom->clone());
5568 : }
5569 : else
5570 : {
5571 0 : CPLErrorReset();
5572 0 : OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
5573 0 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
5574 : {
5575 0 : if (!bSkipFailures)
5576 : {
5577 0 : ret = OGRERR_FAILURE;
5578 0 : goto done;
5579 : }
5580 : else
5581 : {
5582 0 : CPLErrorReset();
5583 0 : ret = OGRERR_NONE;
5584 : }
5585 : }
5586 : else
5587 : {
5588 0 : geom.swap(geom_new);
5589 : }
5590 : }
5591 : }
5592 :
5593 : // possibly add a new feature with area x intersection sum of y
5594 6 : if (geom)
5595 : {
5596 6 : CPLErrorReset();
5597 : OGRGeometryUniquePtr poIntersection(
5598 6 : x_geom->Intersection(geom.get()));
5599 6 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
5600 : {
5601 0 : if (!bSkipFailures)
5602 : {
5603 0 : ret = OGRERR_FAILURE;
5604 0 : goto done;
5605 : }
5606 : else
5607 : {
5608 0 : CPLErrorReset();
5609 0 : ret = OGRERR_NONE;
5610 : }
5611 : }
5612 6 : else if (!poIntersection->IsEmpty())
5613 : {
5614 6 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5615 6 : z->SetFieldsFrom(x.get(), mapInput);
5616 6 : if (bPromoteToMulti)
5617 2 : poIntersection.reset(
5618 : promote_to_multi(poIntersection.release()));
5619 6 : z->SetGeometryDirectly(poIntersection.release());
5620 6 : ret = pLayerResult->CreateFeature(z.get());
5621 6 : if (ret != OGRERR_NONE)
5622 : {
5623 0 : if (!bSkipFailures)
5624 : {
5625 0 : goto done;
5626 : }
5627 : else
5628 : {
5629 0 : CPLErrorReset();
5630 0 : ret = OGRERR_NONE;
5631 : }
5632 : }
5633 : }
5634 : }
5635 : }
5636 3 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5637 : {
5638 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5639 0 : ret = OGRERR_FAILURE;
5640 0 : goto done;
5641 : }
5642 3 : done:
5643 : // release resources
5644 3 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5645 3 : if (pGeometryMethodFilter)
5646 0 : delete pGeometryMethodFilter;
5647 3 : if (mapInput)
5648 3 : VSIFree(mapInput);
5649 3 : return ret;
5650 : }
5651 :
5652 : /************************************************************************/
5653 : /* OGR_L_Clip() */
5654 : /************************************************************************/
5655 :
5656 : /**
5657 : * \brief Clip off areas that are not covered by the method layer.
5658 : *
5659 : * The result layer contains features whose geometries represent areas
5660 : * that are in the input layer and in the method layer. The features
5661 : * in the result layer have the (possibly clipped) areas of features
5662 : * in the input layer and the attributes from the same features. The
5663 : * schema of the result layer can be set by the user or, if it is
5664 : * empty, is initialized to contain all fields in the input layer.
5665 : *
5666 : * \note For best performance use the minimum amount of features in
5667 : * the method layer and copy it into a memory layer.
5668 : *
5669 : * \note This method relies on GEOS support. Do not use unless the
5670 : * GEOS support is compiled in.
5671 : *
5672 : * The recognized list of options is :
5673 : * <ul>
5674 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5675 : * feature could not be inserted or a GEOS call failed.
5676 : * </li>
5677 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5678 : * into MultiPolygons, LineStrings to MultiLineStrings or
5679 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5680 : * </li>
5681 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5682 : * will be created from the fields of the input layer.
5683 : * </li>
5684 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5685 : * will be created from the fields of the method layer.
5686 : * </li>
5687 : * </ul>
5688 : *
5689 : * This function is the same as the C++ method OGRLayer::Clip().
5690 : *
5691 : * @param pLayerInput the input layer. Should not be NULL.
5692 : *
5693 : * @param pLayerMethod the method layer. Should not be NULL.
5694 : *
5695 : * @param pLayerResult the layer where the features resulting from the
5696 : * operation are inserted. Should not be NULL. See above the note
5697 : * about the schema.
5698 : *
5699 : * @param papszOptions NULL terminated list of options (may be NULL).
5700 : *
5701 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5702 : * reporting progress or NULL.
5703 : *
5704 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5705 : *
5706 : * @return an error code if there was an error or the execution was
5707 : * interrupted, OGRERR_NONE otherwise.
5708 : *
5709 : * @note The first geometry field is always used.
5710 : *
5711 : * @since OGR 1.10
5712 : */
5713 :
5714 3 : OGRErr OGR_L_Clip(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5715 : OGRLayerH pLayerResult, char **papszOptions,
5716 : GDALProgressFunc pfnProgress, void *pProgressArg)
5717 :
5718 : {
5719 3 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5720 3 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5721 3 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5722 :
5723 : return OGRLayer::FromHandle(pLayerInput)
5724 3 : ->Clip(OGRLayer::FromHandle(pLayerMethod),
5725 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
5726 3 : pProgressArg);
5727 : }
5728 :
5729 : /************************************************************************/
5730 : /* Erase() */
5731 : /************************************************************************/
5732 :
5733 : /**
5734 : * \brief Remove areas that are covered by the method layer.
5735 : *
5736 : * The result layer contains features whose geometries represent areas
5737 : * that are in the input layer but not in the method layer. The
5738 : * features in the result layer have attributes from the input
5739 : * layer. The schema of the result layer can be set by the user or, if
5740 : * it is empty, is initialized to contain all fields in the input
5741 : * layer.
5742 : *
5743 : * \note For best performance use the minimum amount of features in
5744 : * the method layer and copy it into a memory layer.
5745 : *
5746 : * \note This method relies on GEOS support. Do not use unless the
5747 : * GEOS support is compiled in.
5748 : *
5749 : * The recognized list of options is :
5750 : * <ul>
5751 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5752 : * feature could not be inserted or a GEOS call failed.
5753 : * </li>
5754 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5755 : * into MultiPolygons, LineStrings to MultiLineStrings or
5756 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5757 : * </li>
5758 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5759 : * will be created from the fields of the input layer.
5760 : * </li>
5761 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5762 : * will be created from the fields of the method layer.
5763 : * </li>
5764 : * </ul>
5765 : *
5766 : * This method is the same as the C function OGR_L_Erase().
5767 : *
5768 : * @param pLayerMethod the method layer. Should not be NULL.
5769 : *
5770 : * @param pLayerResult the layer where the features resulting from the
5771 : * operation are inserted. Should not be NULL. See above the note
5772 : * about the schema.
5773 : *
5774 : * @param papszOptions NULL terminated list of options (may be NULL).
5775 : *
5776 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5777 : * reporting progress or NULL.
5778 : *
5779 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5780 : *
5781 : * @return an error code if there was an error or the execution was
5782 : * interrupted, OGRERR_NONE otherwise.
5783 : *
5784 : * @note The first geometry field is always used.
5785 : *
5786 : * @since OGR 1.10
5787 : */
5788 :
5789 6 : OGRErr OGRLayer::Erase(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5790 : char **papszOptions, GDALProgressFunc pfnProgress,
5791 : void *pProgressArg)
5792 : {
5793 6 : OGRErr ret = OGRERR_NONE;
5794 6 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
5795 6 : OGRFeatureDefn *poDefnResult = nullptr;
5796 6 : OGRGeometry *pGeometryMethodFilter = nullptr;
5797 6 : int *mapInput = nullptr;
5798 6 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
5799 6 : double progress_counter = 0;
5800 6 : double progress_ticker = 0;
5801 : const bool bSkipFailures =
5802 6 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5803 6 : const bool bPromoteToMulti = CPLTestBool(
5804 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5805 :
5806 : // check for GEOS
5807 6 : if (!OGRGeometryFactory::haveGEOS())
5808 : {
5809 0 : CPLError(CE_Failure, CPLE_AppDefined,
5810 : "OGRLayer::Erase() requires GEOS support");
5811 0 : return OGRERR_UNSUPPORTED_OPERATION;
5812 : }
5813 :
5814 : // get resources
5815 6 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5816 6 : if (ret != OGRERR_NONE)
5817 0 : goto done;
5818 6 : ret = create_field_map(poDefnInput, &mapInput);
5819 6 : if (ret != OGRERR_NONE)
5820 0 : goto done;
5821 6 : ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
5822 : nullptr, false, papszOptions);
5823 6 : if (ret != OGRERR_NONE)
5824 0 : goto done;
5825 6 : poDefnResult = pLayerResult->GetLayerDefn();
5826 :
5827 18 : for (auto &&x : this)
5828 : {
5829 :
5830 12 : if (pfnProgress)
5831 : {
5832 2 : double p = progress_counter / progress_max;
5833 2 : if (p > progress_ticker)
5834 : {
5835 1 : if (!pfnProgress(p, "", pProgressArg))
5836 : {
5837 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5838 0 : ret = OGRERR_FAILURE;
5839 0 : goto done;
5840 : }
5841 : }
5842 2 : progress_counter += 1.0;
5843 : }
5844 :
5845 : // set up the filter on the method layer
5846 12 : CPLErrorReset();
5847 : OGRGeometry *x_geom =
5848 12 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5849 12 : if (CPLGetLastErrorType() != CE_None)
5850 : {
5851 0 : if (!bSkipFailures)
5852 : {
5853 0 : ret = OGRERR_FAILURE;
5854 0 : goto done;
5855 : }
5856 : else
5857 : {
5858 0 : CPLErrorReset();
5859 0 : ret = OGRERR_NONE;
5860 : }
5861 : }
5862 12 : if (!x_geom)
5863 : {
5864 0 : continue;
5865 : }
5866 :
5867 : OGRGeometryUniquePtr geom(
5868 : x_geom
5869 12 : ->clone()); // this will be the geometry of the result feature
5870 : // incrementally erase y from geom
5871 19 : for (auto &&y : pLayerMethod)
5872 : {
5873 9 : OGRGeometry *y_geom = y->GetGeometryRef();
5874 9 : if (!y_geom)
5875 0 : continue;
5876 9 : CPLErrorReset();
5877 9 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
5878 9 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
5879 : {
5880 0 : if (!bSkipFailures)
5881 : {
5882 0 : ret = OGRERR_FAILURE;
5883 0 : goto done;
5884 : }
5885 : else
5886 : {
5887 0 : CPLErrorReset();
5888 0 : ret = OGRERR_NONE;
5889 : }
5890 : }
5891 : else
5892 : {
5893 9 : geom.swap(geom_new);
5894 9 : if (geom->IsEmpty())
5895 : {
5896 2 : break;
5897 : }
5898 : }
5899 : }
5900 :
5901 : // add a new feature if there is remaining area
5902 12 : if (!geom->IsEmpty())
5903 : {
5904 10 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5905 10 : z->SetFieldsFrom(x.get(), mapInput);
5906 10 : if (bPromoteToMulti)
5907 4 : geom.reset(promote_to_multi(geom.release()));
5908 10 : z->SetGeometryDirectly(geom.release());
5909 10 : ret = pLayerResult->CreateFeature(z.get());
5910 10 : if (ret != OGRERR_NONE)
5911 : {
5912 0 : if (!bSkipFailures)
5913 : {
5914 0 : goto done;
5915 : }
5916 : else
5917 : {
5918 0 : CPLErrorReset();
5919 0 : ret = OGRERR_NONE;
5920 : }
5921 : }
5922 : }
5923 : }
5924 6 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5925 : {
5926 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5927 0 : ret = OGRERR_FAILURE;
5928 0 : goto done;
5929 : }
5930 6 : done:
5931 : // release resources
5932 6 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5933 6 : if (pGeometryMethodFilter)
5934 0 : delete pGeometryMethodFilter;
5935 6 : if (mapInput)
5936 5 : VSIFree(mapInput);
5937 6 : return ret;
5938 : }
5939 :
5940 : /************************************************************************/
5941 : /* OGR_L_Erase() */
5942 : /************************************************************************/
5943 :
5944 : /**
5945 : * \brief Remove areas that are covered by the method layer.
5946 : *
5947 : * The result layer contains features whose geometries represent areas
5948 : * that are in the input layer but not in the method layer. The
5949 : * features in the result layer have attributes from the input
5950 : * layer. The schema of the result layer can be set by the user or, if
5951 : * it is empty, is initialized to contain all fields in the input
5952 : * layer.
5953 : *
5954 : * \note For best performance use the minimum amount of features in
5955 : * the method layer and copy it into a memory layer.
5956 : *
5957 : * \note This method relies on GEOS support. Do not use unless the
5958 : * GEOS support is compiled in.
5959 : *
5960 : * The recognized list of options is :
5961 : * <ul>
5962 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5963 : * feature could not be inserted or a GEOS call failed.
5964 : * </li>
5965 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5966 : * into MultiPolygons, LineStrings to MultiLineStrings or
5967 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5968 : * </li>
5969 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5970 : * will be created from the fields of the input layer.
5971 : * </li>
5972 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5973 : * will be created from the fields of the method layer.
5974 : * </li>
5975 : * </ul>
5976 : *
5977 : * This function is the same as the C++ method OGRLayer::Erase().
5978 : *
5979 : * @param pLayerInput the input layer. Should not be NULL.
5980 : *
5981 : * @param pLayerMethod the method layer. Should not be NULL.
5982 : *
5983 : * @param pLayerResult the layer where the features resulting from the
5984 : * operation are inserted. Should not be NULL. See above the note
5985 : * about the schema.
5986 : *
5987 : * @param papszOptions NULL terminated list of options (may be NULL).
5988 : *
5989 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5990 : * reporting progress or NULL.
5991 : *
5992 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5993 : *
5994 : * @return an error code if there was an error or the execution was
5995 : * interrupted, OGRERR_NONE otherwise.
5996 : *
5997 : * @note The first geometry field is always used.
5998 : *
5999 : * @since OGR 1.10
6000 : */
6001 :
6002 6 : OGRErr OGR_L_Erase(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
6003 : OGRLayerH pLayerResult, char **papszOptions,
6004 : GDALProgressFunc pfnProgress, void *pProgressArg)
6005 :
6006 : {
6007 6 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
6008 6 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
6009 6 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
6010 :
6011 : return OGRLayer::FromHandle(pLayerInput)
6012 6 : ->Erase(OGRLayer::FromHandle(pLayerMethod),
6013 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
6014 6 : pProgressArg);
6015 : }
6016 :
6017 : /************************************************************************/
6018 : /* OGRLayer::FeatureIterator::Private */
6019 : /************************************************************************/
6020 :
6021 : struct OGRLayer::FeatureIterator::Private
6022 : {
6023 : CPL_DISALLOW_COPY_ASSIGN(Private)
6024 35954 : Private() = default;
6025 :
6026 : OGRFeatureUniquePtr m_poFeature{};
6027 : OGRLayer *m_poLayer = nullptr;
6028 : bool m_bError = false;
6029 : bool m_bEOF = true;
6030 : };
6031 :
6032 : /************************************************************************/
6033 : /* OGRLayer::FeatureIterator::FeatureIterator() */
6034 : /************************************************************************/
6035 :
6036 35954 : OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
6037 35954 : : m_poPrivate(new OGRLayer::FeatureIterator::Private())
6038 : {
6039 35954 : m_poPrivate->m_poLayer = poLayer;
6040 35954 : if (bStart)
6041 : {
6042 17977 : if (m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator)
6043 : {
6044 1 : CPLError(CE_Failure, CPLE_NotSupported,
6045 : "Only one feature iterator can be "
6046 : "active at a time");
6047 1 : m_poPrivate->m_bError = true;
6048 : }
6049 : else
6050 : {
6051 17976 : m_poPrivate->m_poLayer->ResetReading();
6052 35952 : m_poPrivate->m_poFeature.reset(
6053 17976 : m_poPrivate->m_poLayer->GetNextFeature());
6054 17976 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
6055 17976 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
6056 : }
6057 : }
6058 35954 : }
6059 :
6060 : /************************************************************************/
6061 : /* ~OGRLayer::FeatureIterator::FeatureIterator() */
6062 : /************************************************************************/
6063 :
6064 35954 : OGRLayer::FeatureIterator::~FeatureIterator()
6065 : {
6066 35954 : if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
6067 35953 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
6068 35954 : }
6069 :
6070 : /************************************************************************/
6071 : /* operator*() */
6072 : /************************************************************************/
6073 :
6074 154107 : OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
6075 : {
6076 154107 : return m_poPrivate->m_poFeature;
6077 : }
6078 :
6079 : /************************************************************************/
6080 : /* operator++() */
6081 : /************************************************************************/
6082 :
6083 153425 : OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
6084 : {
6085 153425 : m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
6086 153425 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
6087 153425 : return *this;
6088 : }
6089 :
6090 : /************************************************************************/
6091 : /* operator!=() */
6092 : /************************************************************************/
6093 :
6094 171402 : bool OGRLayer::FeatureIterator::operator!=(
6095 : const OGRLayer::FeatureIterator &it) const
6096 : {
6097 171402 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
6098 : }
6099 :
6100 : /************************************************************************/
6101 : /* begin() */
6102 : /************************************************************************/
6103 :
6104 17977 : OGRLayer::FeatureIterator OGRLayer::begin()
6105 : {
6106 17977 : return {this, true};
6107 : }
6108 :
6109 : /************************************************************************/
6110 : /* end() */
6111 : /************************************************************************/
6112 :
6113 17977 : OGRLayer::FeatureIterator OGRLayer::end()
6114 : {
6115 17977 : return {this, false};
6116 : }
6117 :
6118 : /************************************************************************/
6119 : /* OGRLayer::GetGeometryTypes() */
6120 : /************************************************************************/
6121 :
6122 : /** \brief Get actual geometry types found in features.
6123 : *
6124 : * This method iterates over features to retrieve their geometry types. This
6125 : * is mostly useful for layers that report a wkbUnknown geometry type with
6126 : * GetGeomType() or GetGeomFieldDefn(iGeomField)->GetType().
6127 : *
6128 : * By default this method returns an array of nEntryCount entries with each
6129 : * geometry type (in OGRGeometryTypeCounter::eGeomType) and the corresponding
6130 : * number of features (in OGRGeometryTypeCounter::nCount).
6131 : * Features without geometries are reported as eGeomType == wkbNone.
6132 : *
6133 : * The nFlagsGGT parameter can be a combination (with binary or operator) of the
6134 : * following hints:
6135 : * <ul>
6136 : * <li>OGR_GGT_COUNT_NOT_NEEDED: to indicate that only the set of geometry types
6137 : * matter, not the number of features per geometry type. Consequently the value
6138 : * of OGRGeometryTypeCounter::nCount should be ignored.</li>
6139 : * <li>OGR_GGT_STOP_IF_MIXED: to indicate that the implementation may stop
6140 : * iterating over features as soon as 2 different geometry types (not counting
6141 : * null geometries) are found. The value of OGRGeometryTypeCounter::nCount
6142 : * should be ignored (zero might be systematically reported by some
6143 : * implementations).</li> <li>OGR_GGT_GEOMCOLLECTIONZ_TINZ: to indicate that if
6144 : * a geometry is of type wkbGeometryCollection25D and its first sub-geometry is
6145 : * of type wkbTINZ, wkbTINZ should be reported as geometry type. This is mostly
6146 : * useful for the ESRI Shapefile and (Open)FileGDB drivers regarding MultiPatch
6147 : * geometries.</li>
6148 : * </ul>
6149 : *
6150 : * If the layer has no features, a non-NULL returned array with nEntryCount == 0
6151 : * will be returned.
6152 : *
6153 : * Spatial and/or attribute filters will be taken into account.
6154 : *
6155 : * This method will error out on a layer without geometry fields
6156 : * (GetGeomType() == wkbNone).
6157 : *
6158 : * A cancellation callback may be provided. The progress percentage it is called
6159 : * with is not relevant. The callback should return TRUE if processing should go
6160 : * on, or FALSE if it should be interrupted.
6161 : *
6162 : * @param iGeomField Geometry field index.
6163 : * @param nFlagsGGT Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
6164 : * OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
6165 : * @param[out] nEntryCountOut Number of entries in the returned array.
6166 : * @param pfnProgress Cancellation callback. May be NULL.
6167 : * @param pProgressData User data for the cancellation callback. May be NULL.
6168 : * @return an array of nEntryCount that must be freed with CPLFree(),
6169 : * or NULL in case of error
6170 : * @since GDAL 3.6
6171 : */
6172 : OGRGeometryTypeCounter *
6173 12 : OGRLayer::GetGeometryTypes(int iGeomField, int nFlagsGGT, int &nEntryCountOut,
6174 : GDALProgressFunc pfnProgress, void *pProgressData)
6175 : {
6176 12 : OGRFeatureDefn *poDefn = GetLayerDefn();
6177 12 : const int nGeomFieldCount = poDefn->GetGeomFieldCount();
6178 12 : if (iGeomField < 0 || iGeomField >= nGeomFieldCount)
6179 : {
6180 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for iGeomField");
6181 1 : nEntryCountOut = 0;
6182 1 : return nullptr;
6183 : }
6184 :
6185 : // Ignore all fields but the geometry one of interest
6186 22 : CPLStringList aosIgnoredFieldsRestore;
6187 22 : CPLStringList aosIgnoredFields;
6188 11 : const int nFieldCount = poDefn->GetFieldCount();
6189 33 : for (int iField = 0; iField < nFieldCount; iField++)
6190 : {
6191 22 : const auto poFieldDefn = poDefn->GetFieldDefn(iField);
6192 22 : const char *pszName = poFieldDefn->GetNameRef();
6193 22 : if (poFieldDefn->IsIgnored())
6194 10 : aosIgnoredFieldsRestore.AddString(pszName);
6195 22 : if (iField != iGeomField)
6196 11 : aosIgnoredFields.AddString(pszName);
6197 : }
6198 33 : for (int iField = 0; iField < nGeomFieldCount; iField++)
6199 : {
6200 22 : const auto poFieldDefn = poDefn->GetGeomFieldDefn(iField);
6201 22 : const char *pszName = poFieldDefn->GetNameRef();
6202 22 : if (poFieldDefn->IsIgnored())
6203 10 : aosIgnoredFieldsRestore.AddString(pszName);
6204 22 : if (iField != iGeomField)
6205 11 : aosIgnoredFields.AddString(pszName);
6206 : }
6207 11 : if (poDefn->IsStyleIgnored())
6208 0 : aosIgnoredFieldsRestore.AddString("OGR_STYLE");
6209 11 : aosIgnoredFields.AddString("OGR_STYLE");
6210 11 : SetIgnoredFields(aosIgnoredFields.List());
6211 :
6212 : // Iterate over features
6213 22 : std::map<OGRwkbGeometryType, int64_t> oMapCount;
6214 22 : std::set<OGRwkbGeometryType> oSetNotNull;
6215 11 : const bool bGeomCollectionZTInZ =
6216 11 : (nFlagsGGT & OGR_GGT_GEOMCOLLECTIONZ_TINZ) != 0;
6217 11 : const bool bStopIfMixed = (nFlagsGGT & OGR_GGT_STOP_IF_MIXED) != 0;
6218 11 : if (pfnProgress == GDALDummyProgress)
6219 0 : pfnProgress = nullptr;
6220 11 : bool bInterrupted = false;
6221 47 : for (auto &&poFeature : *this)
6222 : {
6223 36 : const auto poGeom = poFeature->GetGeomFieldRef(iGeomField);
6224 36 : if (poGeom == nullptr)
6225 : {
6226 18 : ++oMapCount[wkbNone];
6227 : }
6228 : else
6229 : {
6230 18 : auto eGeomType = poGeom->getGeometryType();
6231 18 : if (bGeomCollectionZTInZ && eGeomType == wkbGeometryCollection25D)
6232 : {
6233 1 : const auto poGC = poGeom->toGeometryCollection();
6234 1 : if (poGC->getNumGeometries() > 0)
6235 : {
6236 : auto eSubGeomType =
6237 1 : poGC->getGeometryRef(0)->getGeometryType();
6238 1 : if (eSubGeomType == wkbTINZ)
6239 1 : eGeomType = wkbTINZ;
6240 : }
6241 : }
6242 18 : ++oMapCount[eGeomType];
6243 18 : if (bStopIfMixed)
6244 : {
6245 4 : oSetNotNull.insert(eGeomType);
6246 4 : if (oSetNotNull.size() == 2)
6247 2 : break;
6248 : }
6249 : }
6250 34 : if (pfnProgress && !pfnProgress(0.0, "", pProgressData))
6251 : {
6252 1 : bInterrupted = true;
6253 1 : break;
6254 : }
6255 : }
6256 :
6257 : // Restore ignore fields state
6258 11 : SetIgnoredFields(aosIgnoredFieldsRestore.List());
6259 :
6260 11 : if (bInterrupted)
6261 : {
6262 1 : nEntryCountOut = 0;
6263 1 : return nullptr;
6264 : }
6265 :
6266 : // Format result
6267 10 : nEntryCountOut = static_cast<int>(oMapCount.size());
6268 : OGRGeometryTypeCounter *pasRet = static_cast<OGRGeometryTypeCounter *>(
6269 10 : CPLCalloc(1 + nEntryCountOut, sizeof(OGRGeometryTypeCounter)));
6270 10 : int i = 0;
6271 37 : for (const auto &oIter : oMapCount)
6272 : {
6273 27 : pasRet[i].eGeomType = oIter.first;
6274 27 : pasRet[i].nCount = oIter.second;
6275 27 : ++i;
6276 : }
6277 10 : return pasRet;
6278 : }
6279 :
6280 : /************************************************************************/
6281 : /* OGR_L_GetGeometryTypes() */
6282 : /************************************************************************/
6283 :
6284 : /** \brief Get actual geometry types found in features.
6285 : *
6286 : * See OGRLayer::GetGeometryTypes() for details.
6287 : *
6288 : * @param hLayer Layer.
6289 : * @param iGeomField Geometry field index.
6290 : * @param nFlags Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
6291 : * OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
6292 : * @param[out] pnEntryCount Pointer to the number of entries in the returned
6293 : * array. Must not be NULL.
6294 : * @param pfnProgress Cancellation callback. May be NULL.
6295 : * @param pProgressData User data for the cancellation callback. May be NULL.
6296 : * @return an array of *pnEntryCount that must be freed with CPLFree(),
6297 : * or NULL in case of error
6298 : * @since GDAL 3.6
6299 : */
6300 54 : OGRGeometryTypeCounter *OGR_L_GetGeometryTypes(OGRLayerH hLayer, int iGeomField,
6301 : int nFlags, int *pnEntryCount,
6302 : GDALProgressFunc pfnProgress,
6303 : void *pProgressData)
6304 : {
6305 54 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryTypes", nullptr);
6306 54 : VALIDATE_POINTER1(pnEntryCount, "OGR_L_GetGeometryTypes", nullptr);
6307 :
6308 108 : return OGRLayer::FromHandle(hLayer)->GetGeometryTypes(
6309 54 : iGeomField, nFlags, *pnEntryCount, pfnProgress, pProgressData);
6310 : }
6311 :
6312 : /************************************************************************/
6313 : /* OGRLayer::GetSupportedSRSList() */
6314 : /************************************************************************/
6315 :
6316 : /** \brief Get the list of SRS supported.
6317 : *
6318 : * The base implementation of this method will return an empty list. Some
6319 : * drivers (OAPIF, WFS) may return a non-empty list.
6320 : *
6321 : * One of the SRS returned may be passed to SetActiveSRS() to change the
6322 : * active SRS.
6323 : *
6324 : * @param iGeomField Geometry field index.
6325 : * @return list of supported SRS.
6326 : * @since GDAL 3.7
6327 : */
6328 : const OGRLayer::GetSupportedSRSListRetType &
6329 175 : OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
6330 : {
6331 175 : static OGRLayer::GetSupportedSRSListRetType empty;
6332 175 : return empty;
6333 : }
6334 :
6335 : /************************************************************************/
6336 : /* OGR_L_GetSupportedSRSList() */
6337 : /************************************************************************/
6338 :
6339 : /** \brief Get the list of SRS supported.
6340 : *
6341 : * The base implementation of this method will return an empty list. Some
6342 : * drivers (OAPIF, WFS) may return a non-empty list.
6343 : *
6344 : * One of the SRS returned may be passed to SetActiveSRS() to change the
6345 : * active SRS.
6346 : *
6347 : * @param hLayer Layer.
6348 : * @param iGeomField Geometry field index.
6349 : * @param[out] pnCount Number of values in returned array. Must not be null.
6350 : * @return list of supported SRS, to be freed with OSRFreeSRSArray(), or
6351 : * nullptr
6352 : * @since GDAL 3.7
6353 : */
6354 4 : OGRSpatialReferenceH *OGR_L_GetSupportedSRSList(OGRLayerH hLayer,
6355 : int iGeomField, int *pnCount)
6356 : {
6357 4 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSupportedSRSList", nullptr);
6358 4 : VALIDATE_POINTER1(pnCount, "OGR_L_GetSupportedSRSList", nullptr);
6359 :
6360 : const auto &srsList =
6361 4 : OGRLayer::FromHandle(hLayer)->GetSupportedSRSList(iGeomField);
6362 4 : *pnCount = static_cast<int>(srsList.size());
6363 4 : if (srsList.empty())
6364 : {
6365 2 : return nullptr;
6366 : }
6367 : OGRSpatialReferenceH *pahRet = static_cast<OGRSpatialReferenceH *>(
6368 2 : CPLMalloc((1 + srsList.size()) * sizeof(OGRSpatialReferenceH)));
6369 2 : size_t i = 0;
6370 7 : for (const auto &poSRS : srsList)
6371 : {
6372 5 : poSRS->Reference();
6373 5 : pahRet[i] = OGRSpatialReference::ToHandle(poSRS.get());
6374 5 : ++i;
6375 : }
6376 2 : pahRet[i] = nullptr;
6377 2 : return pahRet;
6378 : }
6379 :
6380 : /************************************************************************/
6381 : /* OGRLayer::SetActiveSRS() */
6382 : /************************************************************************/
6383 :
6384 : /** \brief Change the active SRS.
6385 : *
6386 : * The passed SRS must be in the list returned by GetSupportedSRSList()
6387 : * (the actual pointer may be different, but should be tested as identical
6388 : * with OGRSpatialReference::IsSame()).
6389 : *
6390 : * Changing the active SRS affects:
6391 : * <ul>
6392 : * <li>the SRS in which geometries of returned features are expressed,</li>
6393 : * <li>the SRS in which geometries of passed features (CreateFeature(),
6394 : * SetFeature()) are expressed,</li>
6395 : * <li>the SRS returned by GetSpatialRef() and
6396 : * GetGeomFieldDefn()->GetSpatialRef(),</li>
6397 : * <li>the SRS used to interpret SetSpatialFilter() values.</li>
6398 : * </ul>
6399 : * This also resets feature reading and the spatial filter.
6400 : * Note however that this does not modify the storage SRS of the features of
6401 : * geometries. Said otherwise, this setting is volatile and has no persistent
6402 : * effects after dataset reopening.
6403 : *
6404 : * @param iGeomField Geometry field index.
6405 : * @param poSRS SRS to use
6406 : * @return OGRERR_NONE in case of success, or OGRERR_FAILURE if
6407 : * the passed SRS is not in GetSupportedSRSList()
6408 : * @since GDAL 3.7
6409 : */
6410 1 : OGRErr OGRLayer::SetActiveSRS(CPL_UNUSED int iGeomField,
6411 : CPL_UNUSED const OGRSpatialReference *poSRS)
6412 : {
6413 1 : return OGRERR_FAILURE;
6414 : }
6415 :
6416 : /************************************************************************/
6417 : /* OGR_L_SetActiveSRS() */
6418 : /************************************************************************/
6419 :
6420 : /** \brief Change the active SRS.
6421 : *
6422 : * The passed SRS must be in the list returned by GetSupportedSRSList()
6423 : * (the actual pointer may be different, but should be tested as identical
6424 : * with OGRSpatialReference::IsSame()).
6425 : *
6426 : * Changing the active SRS affects:
6427 : * <ul>
6428 : * <li>the SRS in which geometries of returned features are expressed,</li>
6429 : * <li>the SRS in which geometries of passed features (CreateFeature(),
6430 : * SetFeature()) are expressed,</li>
6431 : * <li>the SRS returned by GetSpatialRef() and
6432 : * GetGeomFieldDefn()->GetSpatialRef(),</li>
6433 : * <li>the SRS used to interpret SetSpatialFilter() values.</li>
6434 : * </ul>
6435 : * This also resets feature reading and the spatial filter.
6436 : * Note however that this does not modify the storage SRS of the features of
6437 : * geometries. Said otherwise, this setting is volatile and has no persistent
6438 : * effects after dataset reopening.
6439 : *
6440 : * @param hLayer Layer.
6441 : * @param iGeomField Geometry field index.
6442 : * @param hSRS SRS to use
6443 : * @return OGRERR_NONE in case of success, OGRERR_FAILURE if
6444 : * the passed SRS is not in GetSupportedSRSList().
6445 : * @since GDAL 3.7
6446 : */
6447 9 : OGRErr OGR_L_SetActiveSRS(OGRLayerH hLayer, int iGeomField,
6448 : OGRSpatialReferenceH hSRS)
6449 : {
6450 9 : VALIDATE_POINTER1(hLayer, "OGR_L_SetActiveSRS", OGRERR_FAILURE);
6451 18 : return OGRLayer::FromHandle(hLayer)->SetActiveSRS(
6452 9 : iGeomField, OGRSpatialReference::FromHandle(hSRS));
6453 : }
6454 :
6455 : /************************************************************************/
6456 : /* GetDataset() */
6457 : /************************************************************************/
6458 :
6459 : /** Return the dataset associated with this layer.
6460 : *
6461 : * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
6462 : * have CreateLayer() capability. It may not be implemented in read-only
6463 : * drivers or out-of-tree drivers.
6464 : *
6465 : * It is currently only used by the GetRecordBatchSchema()
6466 : * method to retrieve the field domain associated with a field, to fill the
6467 : * dictionary field of a struct ArrowSchema.
6468 : * It is also used by CreateFieldFromArrowSchema() to determine which field
6469 : * types and subtypes are supported by the layer, by inspecting the driver
6470 : * metadata, and potentially use fallback types when needed.
6471 : *
6472 : * This method is the same as the C function OGR_L_GetDataset().
6473 : *
6474 : * @return dataset, or nullptr when unknown.
6475 : * @since GDAL 3.6
6476 : */
6477 1 : GDALDataset *OGRLayer::GetDataset()
6478 : {
6479 1 : return nullptr;
6480 : }
6481 :
6482 : /************************************************************************/
6483 : /* OGR_L_GetDataset() */
6484 : /************************************************************************/
6485 :
6486 : /** Return the dataset associated with this layer.
6487 : *
6488 : * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
6489 : * have CreateLayer() capability. It may not be implemented in read-only
6490 : * drivers or out-of-tree drivers.
6491 : *
6492 : * It is currently only used by the GetRecordBatchSchema()
6493 : * method to retrieve the field domain associated with a field, to fill the
6494 : * dictionary field of a struct ArrowSchema.
6495 : * It is also used by CreateFieldFromArrowSchema() to determine which field
6496 : * types and subtypes are supported by the layer, by inspecting the driver
6497 : * metadata, and potentially use fallback types when needed.
6498 : *
6499 : * This function is the same as the C++ method OGRLayer::GetDataset().
6500 : *
6501 : * @return dataset, or nullptr when unknown.
6502 : * @since GDAL 3.9
6503 : */
6504 264 : GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
6505 : {
6506 264 : VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
6507 264 : return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
6508 : }
|