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 71101 : OGRLayer::OGRLayer()
34 71101 : : 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 142202 : m_nFeaturesRead(0)
40 : {
41 71101 : }
42 :
43 : /************************************************************************/
44 : /* ~OGRLayer() */
45 : /************************************************************************/
46 :
47 71046 : OGRLayer::~OGRLayer()
48 :
49 : {
50 71046 : if (m_poStyleTable)
51 : {
52 11 : delete m_poStyleTable;
53 11 : m_poStyleTable = nullptr;
54 : }
55 :
56 71046 : if (m_poAttrIndex != nullptr)
57 : {
58 168 : delete m_poAttrIndex;
59 168 : m_poAttrIndex = nullptr;
60 : }
61 :
62 71046 : if (m_poAttrQuery != nullptr)
63 : {
64 641 : delete m_poAttrQuery;
65 641 : m_poAttrQuery = nullptr;
66 : }
67 :
68 71046 : CPLFree(m_pszAttrQueryString);
69 :
70 71046 : if (m_poFilterGeom)
71 : {
72 876 : delete m_poFilterGeom;
73 876 : m_poFilterGeom = nullptr;
74 : }
75 :
76 71046 : if (m_pPreparedFilterGeom != nullptr)
77 : {
78 876 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
79 876 : m_pPreparedFilterGeom = nullptr;
80 : }
81 :
82 71046 : if (m_poSharedArrowArrayStreamPrivateData != nullptr)
83 : {
84 683 : m_poSharedArrowArrayStreamPrivateData->m_poLayer = nullptr;
85 : }
86 71046 : }
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 13838 : GIntBig OGRLayer::GetFeatureCount(int bForce)
159 :
160 : {
161 13838 : if (!bForce)
162 1 : return -1;
163 :
164 13837 : GIntBig nFeatureCount = 0;
165 55352 : for (auto &&poFeature : *this)
166 : {
167 41515 : CPL_IGNORE_RET_VAL(poFeature.get());
168 41515 : nFeatureCount++;
169 : }
170 13837 : ResetReading();
171 :
172 13837 : return nFeatureCount;
173 : }
174 :
175 : /************************************************************************/
176 : /* OGR_L_GetFeatureCount() */
177 : /************************************************************************/
178 :
179 36896 : GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
180 :
181 : {
182 36896 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
183 :
184 : #ifdef OGRAPISPY_ENABLED
185 36896 : if (bOGRAPISpyEnabled)
186 2 : OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
187 : #endif
188 :
189 36896 : 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 15391 : OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, bool bForce)
225 : {
226 15391 : 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 17473 : OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
260 : {
261 17473 : psExtent->MinX = 0.0;
262 17473 : psExtent->MaxX = 0.0;
263 17473 : psExtent->MinY = 0.0;
264 17473 : 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 34180 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
271 16707 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
272 : {
273 766 : if (iGeomField != 0)
274 : {
275 608 : CPLError(CE_Failure, CPLE_AppDefined,
276 : "Invalid geometry field index : %d", iGeomField);
277 : }
278 766 : return OGRERR_FAILURE;
279 : }
280 :
281 16707 : 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 461 : 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 461 : 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 460 : OGREnvelope oEnv;
321 460 : bool bExtentSet = false;
322 :
323 9895 : for (auto &&poFeature : *this)
324 : {
325 9435 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
326 9435 : if (poGeom == nullptr || poGeom->IsEmpty())
327 : {
328 : /* Do nothing */
329 : }
330 9132 : else if (!bExtentSet)
331 : {
332 410 : poGeom->getEnvelope(psExtent);
333 820 : if (!(std::isnan(psExtent->MinX) || std::isnan(psExtent->MinY) ||
334 410 : std::isnan(psExtent->MaxX) || std::isnan(psExtent->MaxY)))
335 : {
336 410 : bExtentSet = true;
337 : }
338 : }
339 : else
340 : {
341 8722 : poGeom->getEnvelope(&oEnv);
342 8722 : if (oEnv.MinX < psExtent->MinX)
343 321 : psExtent->MinX = oEnv.MinX;
344 8722 : if (oEnv.MinY < psExtent->MinY)
345 372 : psExtent->MinY = oEnv.MinY;
346 8722 : if (oEnv.MaxX > psExtent->MaxX)
347 942 : psExtent->MaxX = oEnv.MaxX;
348 8722 : if (oEnv.MaxY > psExtent->MaxY)
349 929 : psExtent->MaxY = oEnv.MaxY;
350 : }
351 : }
352 460 : ResetReading();
353 :
354 460 : 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 29 : OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
392 :
393 : {
394 29 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
395 :
396 : #ifdef OGRAPISPY_ENABLED
397 29 : if (bOGRAPISpyEnabled)
398 0 : OGRAPISpy_L_GetExtent(hLayer, bForce);
399 : #endif
400 :
401 29 : return OGRLayer::FromHandle(hLayer)->GetExtent(0, psExtent,
402 29 : 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 378 : OGRErr OGR_L_GetExtentEx(OGRLayerH hLayer, int iGeomField,
440 : OGREnvelope *psExtent, int bForce)
441 :
442 : {
443 378 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE);
444 :
445 : #ifdef OGRAPISPY_ENABLED
446 378 : if (bOGRAPISpyEnabled)
447 4 : OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
448 : #endif
449 :
450 378 : return OGRLayer::FromHandle(hLayer)->GetExtent(iGeomField, psExtent,
451 378 : 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 15108 : OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
652 :
653 : {
654 15108 : CPLFree(m_pszAttrQueryString);
655 15108 : m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
656 :
657 : /* -------------------------------------------------------------------- */
658 : /* Are we just clearing any existing query? */
659 : /* -------------------------------------------------------------------- */
660 15108 : if (pszQuery == nullptr || strlen(pszQuery) == 0)
661 : {
662 10063 : if (m_poAttrQuery)
663 : {
664 2855 : delete m_poAttrQuery;
665 2855 : m_poAttrQuery = nullptr;
666 2855 : ResetReading();
667 : }
668 10063 : return OGRERR_NONE;
669 : }
670 :
671 : /* -------------------------------------------------------------------- */
672 : /* Or are we installing a new query? */
673 : /* -------------------------------------------------------------------- */
674 : OGRErr eErr;
675 :
676 5045 : if (!m_poAttrQuery)
677 3554 : m_poAttrQuery = new OGRFeatureQuery();
678 :
679 5045 : eErr = m_poAttrQuery->Compile(this, pszQuery);
680 5045 : if (eErr != OGRERR_NONE)
681 : {
682 3 : delete m_poAttrQuery;
683 3 : m_poAttrQuery = nullptr;
684 : }
685 :
686 5045 : ResetReading();
687 :
688 5045 : return eErr;
689 : }
690 :
691 : /************************************************************************/
692 : /* ContainGeomSpecialField() */
693 : /************************************************************************/
694 :
695 280 : static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
696 : {
697 280 : if (expr->eNodeType == SNT_COLUMN)
698 : {
699 59 : if (expr->table_index == 0 && expr->field_index != -1)
700 : {
701 59 : int nSpecialFieldIdx = expr->field_index - nLayerFieldCount;
702 59 : return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
703 118 : nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
704 59 : nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
705 : }
706 : }
707 221 : else if (expr->eNodeType == SNT_OPERATION)
708 : {
709 333 : for (int i = 0; i < expr->nSubExprCount; i++)
710 : {
711 218 : if (ContainGeomSpecialField(expr->papoSubExpr[i], nLayerFieldCount))
712 0 : return TRUE;
713 : }
714 : }
715 221 : return FALSE;
716 : }
717 :
718 : /************************************************************************/
719 : /* AttributeFilterEvaluationNeedsGeometry() */
720 : /************************************************************************/
721 :
722 : //! @cond Doxygen_Suppress
723 62 : int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
724 : {
725 62 : if (!m_poAttrQuery)
726 0 : return FALSE;
727 :
728 : swq_expr_node *expr =
729 62 : static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
730 62 : int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
731 :
732 62 : return ContainGeomSpecialField(expr, nLayerFieldCount);
733 : }
734 :
735 : //! @endcond
736 :
737 : /************************************************************************/
738 : /* OGR_L_SetAttributeFilter() */
739 : /************************************************************************/
740 :
741 1457 : OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszQuery)
742 :
743 : {
744 1457 : VALIDATE_POINTER1(hLayer, "OGR_L_SetAttributeFilter",
745 : OGRERR_INVALID_HANDLE);
746 :
747 : #ifdef OGRAPISPY_ENABLED
748 1457 : if (bOGRAPISpyEnabled)
749 4 : OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
750 : #endif
751 :
752 1457 : return OGRLayer::FromHandle(hLayer)->SetAttributeFilter(pszQuery);
753 : }
754 :
755 : /************************************************************************/
756 : /* GetFeature() */
757 : /************************************************************************/
758 :
759 1008 : OGRFeature *OGRLayer::GetFeature(GIntBig nFID)
760 :
761 : {
762 : /* Save old attribute and spatial filters */
763 : char *pszOldFilter =
764 1008 : m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
765 : OGRGeometry *poOldFilterGeom =
766 1008 : (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr;
767 1008 : int iOldGeomFieldFilter = m_iGeomFieldFilter;
768 : /* Unset filters */
769 1008 : SetAttributeFilter(nullptr);
770 1008 : SetSpatialFilter(0, nullptr);
771 :
772 1008 : OGRFeatureUniquePtr poFeature;
773 14541 : for (auto &&poFeatureIter : *this)
774 : {
775 13533 : if (poFeatureIter->GetFID() == nFID)
776 : {
777 675 : poFeature.swap(poFeatureIter);
778 675 : break;
779 : }
780 : }
781 :
782 : /* Restore filters */
783 1008 : SetAttributeFilter(pszOldFilter);
784 1008 : CPLFree(pszOldFilter);
785 1008 : SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
786 1008 : delete poOldFilterGeom;
787 :
788 2016 : return poFeature.release();
789 : }
790 :
791 : /************************************************************************/
792 : /* OGR_L_GetFeature() */
793 : /************************************************************************/
794 :
795 2544 : OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
796 :
797 : {
798 2544 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
799 :
800 : #ifdef OGRAPISPY_ENABLED
801 2544 : if (bOGRAPISpyEnabled)
802 2 : OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
803 : #endif
804 :
805 2544 : return OGRFeature::ToHandle(
806 5088 : OGRLayer::FromHandle(hLayer)->GetFeature(nFeatureId));
807 : }
808 :
809 : /************************************************************************/
810 : /* SetNextByIndex() */
811 : /************************************************************************/
812 :
813 1083 : OGRErr OGRLayer::SetNextByIndex(GIntBig nIndex)
814 :
815 : {
816 1083 : if (nIndex < 0)
817 194 : return OGRERR_FAILURE;
818 :
819 889 : ResetReading();
820 :
821 889 : OGRFeature *poFeature = nullptr;
822 129380 : while (nIndex-- > 0)
823 : {
824 128685 : poFeature = GetNextFeature();
825 128685 : if (poFeature == nullptr)
826 194 : return OGRERR_FAILURE;
827 :
828 128491 : delete poFeature;
829 : }
830 :
831 695 : return OGRERR_NONE;
832 : }
833 :
834 : /************************************************************************/
835 : /* OGR_L_SetNextByIndex() */
836 : /************************************************************************/
837 :
838 41 : OGRErr OGR_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
839 :
840 : {
841 41 : VALIDATE_POINTER1(hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE);
842 :
843 : #ifdef OGRAPISPY_ENABLED
844 41 : if (bOGRAPISpyEnabled)
845 2 : OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
846 : #endif
847 :
848 41 : return OGRLayer::FromHandle(hLayer)->SetNextByIndex(nIndex);
849 : }
850 :
851 : /************************************************************************/
852 : /* OGR_L_GetNextFeature() */
853 : /************************************************************************/
854 :
855 84167 : OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
856 :
857 : {
858 84167 : VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
859 :
860 : #ifdef OGRAPISPY_ENABLED
861 84167 : if (bOGRAPISpyEnabled)
862 8 : OGRAPISpy_L_GetNextFeature(hLayer);
863 : #endif
864 :
865 84167 : return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
866 : }
867 :
868 : /************************************************************************/
869 : /* ConvertGeomsIfNecessary() */
870 : /************************************************************************/
871 :
872 967243 : void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
873 : {
874 967243 : if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
875 : {
876 : // One time initialization
877 9428 : m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
878 9428 : m_poPrivate->m_bSupportsCurve =
879 9428 : CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
880 9428 : m_poPrivate->m_bSupportsM =
881 9428 : CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
882 9428 : 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 1844730 : if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
903 877490 : m_poPrivate->m_bApplyGeomSetPrecision)
904 : {
905 89755 : const auto poFeatureDefn = GetLayerDefn();
906 89755 : const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
907 178841 : for (int i = 0; i < nGeomFieldCount; i++)
908 : {
909 89086 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
910 89086 : if (poGeom)
911 : {
912 105413 : if (!m_poPrivate->m_bSupportsM &&
913 19301 : OGR_GT_HasM(poGeom->getGeometryType()))
914 : {
915 1 : poGeom->setMeasured(FALSE);
916 : }
917 :
918 172026 : if (!m_poPrivate->m_bSupportsCurve &&
919 85914 : 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 86112 : 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 967243 : }
952 :
953 : /************************************************************************/
954 : /* SetFeature() */
955 : /************************************************************************/
956 :
957 3587 : OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
958 :
959 : {
960 3587 : ConvertGeomsIfNecessary(poFeature);
961 3587 : return ISetFeature(poFeature);
962 : }
963 :
964 : /************************************************************************/
965 : /* ISetFeature() */
966 : /************************************************************************/
967 :
968 142 : OGRErr OGRLayer::ISetFeature(OGRFeature *)
969 :
970 : {
971 142 : 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 963549 : OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
998 :
999 : {
1000 963549 : ConvertGeomsIfNecessary(poFeature);
1001 963549 : 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 287420 : OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1019 :
1020 : {
1021 287420 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1022 287420 : VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1023 :
1024 : #ifdef OGRAPISPY_ENABLED
1025 287420 : if (bOGRAPISpyEnabled)
1026 5 : OGRAPISpy_L_CreateFeature(hLayer, hFeat);
1027 : #endif
1028 :
1029 287420 : return OGRLayer::FromHandle(hLayer)->CreateFeature(
1030 287420 : 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 77521 : OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
1190 :
1191 : {
1192 77521 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1193 77521 : VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1194 :
1195 : #ifdef OGRAPISPY_ENABLED
1196 77521 : if (bOGRAPISpyEnabled)
1197 6 : OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
1198 : #endif
1199 :
1200 155042 : return OGRLayer::FromHandle(hLayer)->CreateField(
1201 77521 : 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 373 : OGRErr OGR_L_DeleteField(OGRLayerH hLayer, int iField)
1224 :
1225 : {
1226 373 : VALIDATE_POINTER1(hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE);
1227 :
1228 : #ifdef OGRAPISPY_ENABLED
1229 373 : if (bOGRAPISpyEnabled)
1230 2 : OGRAPISpy_L_DeleteField(hLayer, iField);
1231 : #endif
1232 :
1233 373 : 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 132 : OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
1436 : int bApproxOK)
1437 :
1438 : {
1439 132 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1440 132 : VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1441 :
1442 : #ifdef OGRAPISPY_ENABLED
1443 132 : if (bOGRAPISpyEnabled)
1444 2 : OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
1445 : #endif
1446 :
1447 264 : return OGRLayer::FromHandle(hLayer)->CreateGeomField(
1448 132 : OGRGeomFieldDefn::FromHandle(hField), bApproxOK);
1449 : }
1450 :
1451 : /************************************************************************/
1452 : /* StartTransaction() */
1453 : /************************************************************************/
1454 :
1455 717 : OGRErr OGRLayer::StartTransaction()
1456 :
1457 : {
1458 717 : return OGRERR_NONE;
1459 : }
1460 :
1461 : /************************************************************************/
1462 : /* OGR_L_StartTransaction() */
1463 : /************************************************************************/
1464 :
1465 160 : OGRErr OGR_L_StartTransaction(OGRLayerH hLayer)
1466 :
1467 : {
1468 160 : VALIDATE_POINTER1(hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE);
1469 :
1470 : #ifdef OGRAPISPY_ENABLED
1471 160 : if (bOGRAPISpyEnabled)
1472 2 : OGRAPISpy_L_StartTransaction(hLayer);
1473 : #endif
1474 :
1475 160 : return OGRLayer::FromHandle(hLayer)->StartTransaction();
1476 : }
1477 :
1478 : /************************************************************************/
1479 : /* CommitTransaction() */
1480 : /************************************************************************/
1481 :
1482 673 : OGRErr OGRLayer::CommitTransaction()
1483 :
1484 : {
1485 673 : return OGRERR_NONE;
1486 : }
1487 :
1488 : /************************************************************************/
1489 : /* OGR_L_CommitTransaction() */
1490 : /************************************************************************/
1491 :
1492 140 : OGRErr OGR_L_CommitTransaction(OGRLayerH hLayer)
1493 :
1494 : {
1495 140 : VALIDATE_POINTER1(hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE);
1496 :
1497 : #ifdef OGRAPISPY_ENABLED
1498 140 : if (bOGRAPISpyEnabled)
1499 2 : OGRAPISpy_L_CommitTransaction(hLayer);
1500 : #endif
1501 :
1502 140 : 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 132423 : OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
1538 :
1539 : {
1540 132423 : VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
1541 :
1542 : #ifdef OGRAPISPY_ENABLED
1543 132423 : if (bOGRAPISpyEnabled)
1544 15 : OGRAPISpy_L_GetLayerDefn(hLayer);
1545 : #endif
1546 :
1547 132423 : return OGRFeatureDefn::ToHandle(
1548 264846 : 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 429437 : OGRSpatialReference *OGRLayer::GetSpatialRef()
1585 : {
1586 429437 : if (GetLayerDefn()->GetGeomFieldCount() > 0)
1587 : return const_cast<OGRSpatialReference *>(
1588 428973 : GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef());
1589 : else
1590 464 : return nullptr;
1591 : }
1592 :
1593 : /************************************************************************/
1594 : /* OGR_L_GetSpatialRef() */
1595 : /************************************************************************/
1596 :
1597 1063 : OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
1598 :
1599 : {
1600 1063 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
1601 :
1602 : #ifdef OGRAPISPY_ENABLED
1603 1063 : if (bOGRAPISpyEnabled)
1604 2 : OGRAPISpy_L_GetSpatialRef(hLayer);
1605 : #endif
1606 :
1607 1063 : return OGRSpatialReference::ToHandle(
1608 2126 : OGRLayer::FromHandle(hLayer)->GetSpatialRef());
1609 : }
1610 :
1611 : /************************************************************************/
1612 : /* OGR_L_TestCapability() */
1613 : /************************************************************************/
1614 :
1615 921 : int OGR_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
1616 :
1617 : {
1618 921 : VALIDATE_POINTER1(hLayer, "OGR_L_TestCapability", 0);
1619 921 : VALIDATE_POINTER1(pszCap, "OGR_L_TestCapability", 0);
1620 :
1621 : #ifdef OGRAPISPY_ENABLED
1622 921 : if (bOGRAPISpyEnabled)
1623 2 : OGRAPISpy_L_TestCapability(hLayer, pszCap);
1624 : #endif
1625 :
1626 921 : return OGRLayer::FromHandle(hLayer)->TestCapability(pszCap);
1627 : }
1628 :
1629 : /************************************************************************/
1630 : /* GetSpatialFilter() */
1631 : /************************************************************************/
1632 :
1633 418 : OGRGeometry *OGRLayer::GetSpatialFilter()
1634 :
1635 : {
1636 418 : 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 53534 : bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
1663 : int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
1664 : {
1665 53534 : 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 106828 : else if (iGeomField < 0 ||
1673 53294 : 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 52973 : 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 6949 : OGRErr OGRLayer::SetSpatialFilter(const OGRGeometry *poFilter)
1734 :
1735 : {
1736 6949 : 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 66153 : OGRErr OGRLayer::SetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
1776 :
1777 : {
1778 66153 : if (iGeomField == 0)
1779 : {
1780 116739 : if (poFilter &&
1781 52059 : !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 65592 : 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 37172 : OGRErr OGRLayer::ISetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
1822 :
1823 : {
1824 37172 : m_iGeomFieldFilter = iGeomField;
1825 37172 : if (InstallFilter(poFilter))
1826 28784 : ResetReading();
1827 37172 : 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 48042 : OGRErr OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY,
1970 : double dfMaxX, double dfMaxY)
1971 :
1972 : {
1973 48042 : 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 48096 : OGRErr OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
2006 : double dfMinY, double dfMaxX,
2007 : double dfMaxY)
2008 :
2009 : {
2010 96192 : auto poRing = std::make_unique<OGRLinearRing>();
2011 96192 : OGRPolygon oPoly;
2012 :
2013 48096 : poRing->addPoint(dfMinX, dfMinY);
2014 48096 : poRing->addPoint(dfMinX, dfMaxY);
2015 48096 : poRing->addPoint(dfMaxX, dfMaxY);
2016 48096 : poRing->addPoint(dfMaxX, dfMinY);
2017 48096 : poRing->addPoint(dfMinX, dfMinY);
2018 :
2019 48096 : oPoly.addRing(std::move(poRing));
2020 :
2021 96192 : 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 64731 : int OGRLayer::InstallFilter(const OGRGeometry *poFilter)
2137 :
2138 : {
2139 64731 : if (m_poFilterGeom == poFilter)
2140 10504 : return FALSE;
2141 :
2142 : /* -------------------------------------------------------------------- */
2143 : /* Replace the existing filter. */
2144 : /* -------------------------------------------------------------------- */
2145 54227 : if (m_poFilterGeom != nullptr)
2146 : {
2147 51319 : delete m_poFilterGeom;
2148 51319 : m_poFilterGeom = nullptr;
2149 : }
2150 :
2151 54227 : if (m_pPreparedFilterGeom != nullptr)
2152 : {
2153 51319 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
2154 51319 : m_pPreparedFilterGeom = nullptr;
2155 : }
2156 :
2157 54227 : if (poFilter != nullptr)
2158 52195 : m_poFilterGeom = poFilter->clone();
2159 :
2160 54227 : m_bFilterIsEnvelope = FALSE;
2161 :
2162 54227 : if (m_poFilterGeom == nullptr)
2163 2032 : return TRUE;
2164 :
2165 52195 : m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
2166 :
2167 : /* Compile geometry filter as a prepared geometry */
2168 52195 : m_pPreparedFilterGeom =
2169 52195 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
2170 :
2171 52195 : m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
2172 :
2173 52195 : return TRUE;
2174 : }
2175 :
2176 : //! @endcond
2177 :
2178 : /************************************************************************/
2179 : /* DoesGeometryHavePointInEnvelope() */
2180 : /************************************************************************/
2181 :
2182 5566 : static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
2183 : const OGREnvelope &sEnvelope)
2184 : {
2185 5566 : const OGRLineString *poLS = nullptr;
2186 :
2187 5566 : 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 4395 : case wkbPolygon:
2203 : {
2204 4395 : const OGRPolygon *poPoly = poGeometry->toPolygon();
2205 4395 : poLS = poPoly->getExteriorRing();
2206 4395 : break;
2207 : }
2208 :
2209 500 : case wkbMultiPoint:
2210 : case wkbMultiLineString:
2211 : case wkbMultiPolygon:
2212 : case wkbGeometryCollection:
2213 : {
2214 732 : for (const auto &poSubGeom : *(poGeometry->toGeometryCollection()))
2215 : {
2216 646 : if (DoesGeometryHavePointInEnvelope(poSubGeom, sEnvelope))
2217 414 : return true;
2218 : }
2219 86 : return false;
2220 : }
2221 :
2222 241 : default:
2223 241 : return false;
2224 : }
2225 :
2226 4789 : if (poLS != nullptr)
2227 : {
2228 4789 : const int nNumPoints = poLS->getNumPoints();
2229 55829 : for (int i = 0; i < nNumPoints; i++)
2230 : {
2231 54713 : const double x = poLS->getX(i);
2232 54713 : const double y = poLS->getY(i);
2233 54713 : if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
2234 21912 : x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
2235 : {
2236 3673 : return true;
2237 : }
2238 : }
2239 : }
2240 :
2241 1116 : 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 461530 : 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 461530 : if (m_poFilterGeom == nullptr)
2262 376 : return TRUE;
2263 :
2264 461154 : 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 460851 : OGREnvelope sGeomEnv;
2273 :
2274 460851 : poGeometry->getEnvelope(&sGeomEnv);
2275 :
2276 460851 : if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
2277 302498 : sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
2278 232303 : m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
2279 132834 : m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
2280 344560 : 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 116291 : if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
2288 111061 : sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
2289 109769 : sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
2290 108890 : sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
2291 : {
2292 108510 : 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 7781 : if (m_bFilterIsEnvelope)
2300 : {
2301 4920 : if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
2302 3683 : 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 4098 : if (OGRGeometryFactory::haveGEOS())
2312 : {
2313 : // CPLDebug("OGRLayer", "GEOS intersection");
2314 4098 : if (m_pPreparedFilterGeom != nullptr)
2315 4098 : return OGRPreparedGeometryIntersects(
2316 : m_pPreparedFilterGeom,
2317 : OGRGeometry::ToHandle(
2318 4098 : 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 2671 : void OGRLayer::PrepareStartTransaction()
2410 : {
2411 2671 : m_apoFieldDefnChanges.clear();
2412 2671 : m_apoGeomFieldDefnChanges.clear();
2413 2671 : }
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 17718 : void OGR_L_ResetReading(OGRLayerH hLayer)
2604 :
2605 : {
2606 17718 : VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
2607 :
2608 : #ifdef OGRAPISPY_ENABLED
2609 17718 : if (bOGRAPISpyEnabled)
2610 2 : OGRAPISpy_L_ResetReading(hLayer);
2611 : #endif
2612 :
2613 17718 : 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 664 : OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
2627 :
2628 : {
2629 : #ifdef HAVE_MITAB
2630 : OGRErr eErr;
2631 :
2632 664 : if (m_poAttrIndex != nullptr)
2633 496 : return OGRERR_NONE;
2634 :
2635 168 : m_poAttrIndex = OGRCreateDefaultLayerIndex();
2636 :
2637 168 : eErr = m_poAttrIndex->Initialize(pszFilename, this);
2638 168 : if (eErr != OGRERR_NONE)
2639 : {
2640 0 : delete m_poAttrIndex;
2641 0 : m_poAttrIndex = nullptr;
2642 : }
2643 :
2644 168 : return eErr;
2645 : #else
2646 : return OGRERR_FAILURE;
2647 : #endif
2648 : }
2649 :
2650 : //! @endcond
2651 :
2652 : /************************************************************************/
2653 : /* SyncToDisk() */
2654 : /************************************************************************/
2655 :
2656 5653 : OGRErr OGRLayer::SyncToDisk()
2657 :
2658 : {
2659 5653 : 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 318 : OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
2684 : {
2685 318 : 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 7686 : const char *OGRLayer::GetFIDColumn()
2735 :
2736 : {
2737 7686 : return "";
2738 : }
2739 :
2740 : /************************************************************************/
2741 : /* OGR_L_GetFIDColumn() */
2742 : /************************************************************************/
2743 :
2744 389 : const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
2745 :
2746 : {
2747 389 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
2748 :
2749 : #ifdef OGRAPISPY_ENABLED
2750 389 : if (bOGRAPISpyEnabled)
2751 2 : OGRAPISpy_L_GetFIDColumn(hLayer);
2752 : #endif
2753 :
2754 389 : return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
2755 : }
2756 :
2757 : /************************************************************************/
2758 : /* GetGeometryColumn() */
2759 : /************************************************************************/
2760 :
2761 3561 : const char *OGRLayer::GetGeometryColumn()
2762 :
2763 : {
2764 3561 : if (GetLayerDefn()->GetGeomFieldCount() > 0)
2765 3481 : 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 1023 : OGRStyleTable *OGRLayer::GetStyleTable()
2792 : {
2793 1023 : 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 1020 : void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
2812 : {
2813 1020 : if (m_poStyleTable)
2814 0 : delete m_poStyleTable;
2815 1020 : if (poStyleTable)
2816 1 : m_poStyleTable = poStyleTable->Clone();
2817 1020 : }
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 1122930 : const char *OGRLayer::GetName()
2864 :
2865 : {
2866 1122930 : return GetLayerDefn()->GetName();
2867 : }
2868 :
2869 : /************************************************************************/
2870 : /* OGR_L_GetName() */
2871 : /************************************************************************/
2872 :
2873 1269 : const char *OGR_L_GetName(OGRLayerH hLayer)
2874 :
2875 : {
2876 1269 : VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
2877 :
2878 : #ifdef OGRAPISPY_ENABLED
2879 1269 : if (bOGRAPISpyEnabled)
2880 2 : OGRAPISpy_L_GetName(hLayer);
2881 : #endif
2882 :
2883 1269 : return OGRLayer::FromHandle(hLayer)->GetName();
2884 : }
2885 :
2886 : /************************************************************************/
2887 : /* GetGeomType() */
2888 : /************************************************************************/
2889 :
2890 217733 : OGRwkbGeometryType OGRLayer::GetGeomType()
2891 : {
2892 217733 : OGRFeatureDefn *poLayerDefn = GetLayerDefn();
2893 217733 : if (poLayerDefn == nullptr)
2894 : {
2895 0 : CPLDebug("OGR", "GetLayerType() returns NULL !");
2896 0 : return wkbUnknown;
2897 : }
2898 217733 : return poLayerDefn->GetGeomType();
2899 : }
2900 :
2901 : /************************************************************************/
2902 : /* OGR_L_GetGeomType() */
2903 : /************************************************************************/
2904 :
2905 1114 : OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
2906 :
2907 : {
2908 1114 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
2909 :
2910 : #ifdef OGRAPISPY_ENABLED
2911 1114 : if (bOGRAPISpyEnabled)
2912 2 : OGRAPISpy_L_GetGeomType(hLayer);
2913 : #endif
2914 :
2915 1114 : OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
2916 1114 : if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
2917 : {
2918 1 : eType = OGR_GT_GetLinear(eType);
2919 : }
2920 1114 : return eType;
2921 : }
2922 :
2923 : /************************************************************************/
2924 : /* SetIgnoredFields() */
2925 : /************************************************************************/
2926 :
2927 8572 : OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
2928 : {
2929 8572 : OGRFeatureDefn *poDefn = GetLayerDefn();
2930 :
2931 : // first set everything as *not* ignored
2932 63551 : for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
2933 : {
2934 54979 : poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
2935 : }
2936 19800 : for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
2937 : {
2938 11228 : poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
2939 : }
2940 8572 : poDefn->SetStyleIgnored(FALSE);
2941 :
2942 : // ignore some fields
2943 16055 : for (const char *pszFieldName : cpl::Iterate(papszFields))
2944 : {
2945 : // check special fields
2946 7483 : if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
2947 156 : poDefn->SetGeometryIgnored(TRUE);
2948 7327 : else if (EQUAL(pszFieldName, "OGR_STYLE"))
2949 13 : poDefn->SetStyleIgnored(TRUE);
2950 : else
2951 : {
2952 : // check ordinary fields
2953 7314 : int iField = poDefn->GetFieldIndex(pszFieldName);
2954 7314 : 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 5676 : poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
2967 : }
2968 : }
2969 :
2970 8572 : 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 79 : static OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
3055 : {
3056 79 : OGRErr ret = OGRERR_NONE;
3057 79 : OGRGeometry *g = pLayer->GetSpatialFilter();
3058 79 : *ppGeometry = g ? g->clone() : nullptr;
3059 79 : return ret;
3060 : }
3061 :
3062 101 : static OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
3063 : {
3064 101 : OGRErr ret = OGRERR_NONE;
3065 101 : int n = poDefn->GetFieldCount();
3066 101 : if (n > 0)
3067 : {
3068 73 : *map = static_cast<int *>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
3069 73 : if (!(*map))
3070 0 : return OGRERR_NOT_ENOUGH_MEMORY;
3071 221 : for (int i = 0; i < n; i++)
3072 148 : (*map)[i] = -1;
3073 : }
3074 101 : return ret;
3075 : }
3076 :
3077 56 : 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 56 : if (!CPLTestBool(CSLFetchNameValueDef(papszOptions, "ADD_FIELDS", "YES")))
3084 0 : return OGRERR_NONE;
3085 :
3086 56 : OGRErr ret = OGRERR_NONE;
3087 56 : OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
3088 : const char *pszInputPrefix =
3089 56 : CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
3090 : const char *pszMethodPrefix =
3091 56 : CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
3092 : const bool bSkipFailures =
3093 56 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3094 56 : if (poDefnResult->GetFieldCount() > 0)
3095 : {
3096 : // the user has defined the schema of the output layer
3097 17 : if (mapInput)
3098 : {
3099 48 : for (int iField = 0; iField < poDefnInput->GetFieldCount();
3100 : iField++)
3101 : {
3102 : CPLString osName(
3103 31 : poDefnInput->GetFieldDefn(iField)->GetNameRef());
3104 31 : if (pszInputPrefix != nullptr)
3105 17 : osName = pszInputPrefix + osName;
3106 31 : mapInput[iField] = poDefnResult->GetFieldIndex(osName);
3107 : }
3108 : }
3109 17 : if (!mapMethod)
3110 4 : return ret;
3111 : // cppcheck-suppress nullPointer
3112 40 : for (int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++)
3113 : {
3114 : // cppcheck-suppress nullPointer
3115 27 : CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
3116 27 : if (pszMethodPrefix != nullptr)
3117 17 : osName = pszMethodPrefix + osName;
3118 27 : mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
3119 : }
3120 : }
3121 : else
3122 : {
3123 : // use schema from the input layer or from input and method layers
3124 39 : const int nFieldsInput = poDefnInput->GetFieldCount();
3125 :
3126 : // If no prefix is specified and we have input+method layers, make
3127 : // sure we will generate unique field names
3128 39 : std::set<std::string> oSetInputFieldNames;
3129 39 : std::set<std::string> oSetMethodFieldNames;
3130 39 : if (poDefnMethod != nullptr && pszInputPrefix == nullptr &&
3131 : pszMethodPrefix == nullptr)
3132 : {
3133 72 : for (int iField = 0; iField < nFieldsInput; iField++)
3134 : {
3135 : oSetInputFieldNames.insert(
3136 40 : poDefnInput->GetFieldDefn(iField)->GetNameRef());
3137 : }
3138 32 : const int nFieldsMethod = poDefnMethod->GetFieldCount();
3139 70 : for (int iField = 0; iField < nFieldsMethod; iField++)
3140 : {
3141 : oSetMethodFieldNames.insert(
3142 38 : poDefnMethod->GetFieldDefn(iField)->GetNameRef());
3143 : }
3144 : }
3145 :
3146 39 : const bool bAddInputFields = CPLTestBool(
3147 : CSLFetchNameValueDef(papszOptions, "ADD_INPUT_FIELDS", "YES"));
3148 39 : if (bAddInputFields)
3149 : {
3150 75 : for (int iField = 0; iField < nFieldsInput; iField++)
3151 : {
3152 40 : OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
3153 40 : if (pszInputPrefix != nullptr)
3154 0 : oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix,
3155 : oFieldDefn.GetNameRef()));
3156 66 : else if (!oSetMethodFieldNames.empty() &&
3157 66 : oSetMethodFieldNames.find(oFieldDefn.GetNameRef()) !=
3158 66 : oSetMethodFieldNames.end())
3159 : {
3160 : // Field of same name present in method layer
3161 17 : oFieldDefn.SetName(
3162 : CPLSPrintf("input_%s", oFieldDefn.GetNameRef()));
3163 : }
3164 40 : ret = pLayerResult->CreateField(&oFieldDefn);
3165 40 : if (ret != OGRERR_NONE)
3166 : {
3167 0 : if (!bSkipFailures)
3168 0 : return ret;
3169 : else
3170 : {
3171 0 : CPLErrorReset();
3172 0 : ret = OGRERR_NONE;
3173 : }
3174 : }
3175 40 : if (mapInput)
3176 40 : mapInput[iField] =
3177 40 : pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
3178 : }
3179 : }
3180 :
3181 39 : if (!combined)
3182 11 : return ret;
3183 28 : if (!mapMethod)
3184 12 : return ret;
3185 16 : if (!poDefnMethod)
3186 0 : return ret;
3187 :
3188 16 : const bool bAddMethodFields = CPLTestBool(
3189 : CSLFetchNameValueDef(papszOptions, "ADD_METHOD_FIELDS", "YES"));
3190 16 : if (bAddMethodFields)
3191 : {
3192 12 : const int nFieldsMethod = poDefnMethod->GetFieldCount();
3193 34 : for (int iField = 0; iField < nFieldsMethod; iField++)
3194 : {
3195 22 : OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
3196 22 : if (pszMethodPrefix != nullptr)
3197 0 : oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix,
3198 : oFieldDefn.GetNameRef()));
3199 44 : else if (!oSetInputFieldNames.empty() &&
3200 44 : oSetInputFieldNames.find(oFieldDefn.GetNameRef()) !=
3201 44 : oSetInputFieldNames.end())
3202 : {
3203 : // Field of same name present in method layer
3204 15 : oFieldDefn.SetName(
3205 : CPLSPrintf("method_%s", oFieldDefn.GetNameRef()));
3206 : }
3207 22 : ret = pLayerResult->CreateField(&oFieldDefn);
3208 22 : if (ret != OGRERR_NONE)
3209 : {
3210 0 : if (!bSkipFailures)
3211 0 : return ret;
3212 : else
3213 : {
3214 0 : CPLErrorReset();
3215 0 : ret = OGRERR_NONE;
3216 : }
3217 : }
3218 22 : mapMethod[iField] =
3219 22 : pLayerResult->GetLayerDefn()->GetFieldCount() - 1;
3220 : }
3221 : }
3222 : }
3223 29 : return ret;
3224 : }
3225 :
3226 310 : static OGRGeometry *set_filter_from(OGRLayer *pLayer,
3227 : OGRGeometry *pGeometryExistingFilter,
3228 : OGRFeature *pFeature)
3229 : {
3230 310 : OGRGeometry *geom = pFeature->GetGeometryRef();
3231 310 : if (!geom)
3232 0 : return nullptr;
3233 310 : if (pGeometryExistingFilter)
3234 : {
3235 0 : if (!geom->Intersects(pGeometryExistingFilter))
3236 0 : return nullptr;
3237 0 : OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
3238 0 : if (intersection)
3239 : {
3240 0 : pLayer->SetSpatialFilter(intersection);
3241 0 : delete intersection;
3242 : }
3243 : else
3244 0 : return nullptr;
3245 : }
3246 : else
3247 : {
3248 310 : pLayer->SetSpatialFilter(geom);
3249 : }
3250 310 : return geom;
3251 : }
3252 :
3253 26 : static OGRGeometry *promote_to_multi(OGRGeometry *poGeom)
3254 : {
3255 26 : OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
3256 26 : if (eType == wkbPoint)
3257 4 : return OGRGeometryFactory::forceToMultiPoint(poGeom);
3258 22 : else if (eType == wkbPolygon)
3259 22 : return OGRGeometryFactory::forceToMultiPolygon(poGeom);
3260 0 : else if (eType == wkbLineString)
3261 0 : return OGRGeometryFactory::forceToMultiLineString(poGeom);
3262 : else
3263 0 : return poGeom;
3264 : }
3265 :
3266 : /************************************************************************/
3267 : /* Intersection() */
3268 : /************************************************************************/
3269 : /**
3270 : * \brief Intersection of two layers.
3271 : *
3272 : * The result layer contains features whose geometries represent areas
3273 : * that are common between features in the input layer and in the
3274 : * method layer. The features in the result layer have attributes from
3275 : * both input and method layers. The schema of the result layer can be
3276 : * set by the user or, if it is empty, is initialized to contain all
3277 : * fields in the input and method layers.
3278 : *
3279 : * \note If the schema of the result is set by user and contains
3280 : * fields that have the same name as a field in input and in method
3281 : * layer, then the attribute in the result feature will get the value
3282 : * from the feature of the method layer.
3283 : *
3284 : * \note For best performance use the minimum amount of features in
3285 : * the method layer and copy it into a memory layer.
3286 : *
3287 : * \note This method relies on GEOS support. Do not use unless the
3288 : * GEOS support is compiled in.
3289 : *
3290 : * The recognized list of options is:
3291 : * <ul>
3292 : * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
3293 : * feature could not be inserted or a GEOS call failed.
3294 : * </li>
3295 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3296 : * into MultiPolygons, LineStrings to MultiLineStrings or
3297 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
3298 : * </li>
3299 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3300 : * will be created from the fields of the input layer.
3301 : * </li>
3302 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3303 : * will be created from the fields of the method layer.
3304 : * </li>
3305 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3306 : * geometries to pretest intersection of features of method layer
3307 : * with features of this layer.
3308 : * </li>
3309 : * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
3310 : * containment of features of method layer within the features of
3311 : * this layer. This will speed up the method significantly in some
3312 : * cases. Requires that the prepared geometries are in effect.
3313 : * </li>
3314 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3315 : * result features with lower dimension geometry that would
3316 : * otherwise be added to the result layer. The default is YES, to add
3317 : * features with lower dimension geometry, but only if the result layer
3318 : * has an unknown geometry type.
3319 : * </li>
3320 : * </ul>
3321 : *
3322 : * This method is the same as the C function OGR_L_Intersection().
3323 : *
3324 : * @param pLayerMethod the method layer. Should not be NULL.
3325 : *
3326 : * @param pLayerResult the layer where the features resulting from the
3327 : * operation are inserted. Should not be NULL. See above the note
3328 : * about the schema.
3329 : *
3330 : * @param papszOptions NULL terminated list of options (may be NULL).
3331 : *
3332 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3333 : * reporting progress or NULL.
3334 : *
3335 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3336 : *
3337 : * @return an error code if there was an error or the execution was
3338 : * interrupted, OGRERR_NONE otherwise.
3339 : *
3340 : * @note The first geometry field is always used.
3341 : *
3342 : * @since OGR 1.10
3343 : */
3344 :
3345 9 : OGRErr OGRLayer::Intersection(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
3346 : char **papszOptions, GDALProgressFunc pfnProgress,
3347 : void *pProgressArg)
3348 : {
3349 9 : OGRErr ret = OGRERR_NONE;
3350 9 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
3351 9 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3352 9 : OGRFeatureDefn *poDefnResult = nullptr;
3353 9 : OGRGeometry *pGeometryMethodFilter = nullptr;
3354 9 : int *mapInput = nullptr;
3355 9 : int *mapMethod = nullptr;
3356 9 : OGREnvelope sEnvelopeMethod;
3357 : GBool bEnvelopeSet;
3358 9 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
3359 9 : double progress_counter = 0;
3360 9 : double progress_ticker = 0;
3361 : const bool bSkipFailures =
3362 9 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3363 9 : const bool bPromoteToMulti = CPLTestBool(
3364 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3365 9 : const bool bUsePreparedGeometries = CPLTestBool(
3366 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
3367 9 : const bool bPretestContainment = CPLTestBool(
3368 : CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
3369 9 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
3370 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
3371 :
3372 : // check for GEOS
3373 9 : if (!OGRGeometryFactory::haveGEOS())
3374 : {
3375 0 : CPLError(CE_Failure, CPLE_AppDefined,
3376 : "OGRLayer::Intersection() requires GEOS support");
3377 0 : return OGRERR_UNSUPPORTED_OPERATION;
3378 : }
3379 :
3380 : // get resources
3381 9 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3382 9 : if (ret != OGRERR_NONE)
3383 0 : goto done;
3384 9 : ret = create_field_map(poDefnInput, &mapInput);
3385 9 : if (ret != OGRERR_NONE)
3386 0 : goto done;
3387 9 : ret = create_field_map(poDefnMethod, &mapMethod);
3388 9 : if (ret != OGRERR_NONE)
3389 0 : goto done;
3390 9 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
3391 : mapMethod, true, papszOptions);
3392 9 : if (ret != OGRERR_NONE)
3393 0 : goto done;
3394 9 : poDefnResult = pLayerResult->GetLayerDefn();
3395 9 : bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
3396 9 : if (bKeepLowerDimGeom)
3397 : {
3398 : // require that the result layer is of geom type unknown
3399 7 : if (pLayerResult->GetGeomType() != wkbUnknown)
3400 : {
3401 1 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
3402 : "since the result layer does not allow it.");
3403 1 : bKeepLowerDimGeom = false;
3404 : }
3405 : }
3406 :
3407 25 : for (auto &&x : this)
3408 : {
3409 :
3410 16 : if (pfnProgress)
3411 : {
3412 3 : double p = progress_counter / progress_max;
3413 3 : if (p > progress_ticker)
3414 : {
3415 1 : if (!pfnProgress(p, "", pProgressArg))
3416 : {
3417 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3418 0 : ret = OGRERR_FAILURE;
3419 0 : goto done;
3420 : }
3421 : }
3422 3 : progress_counter += 1.0;
3423 : }
3424 :
3425 : // is it worth to proceed?
3426 16 : if (bEnvelopeSet)
3427 : {
3428 16 : OGRGeometry *x_geom = x->GetGeometryRef();
3429 16 : if (x_geom)
3430 : {
3431 16 : OGREnvelope x_env;
3432 16 : x_geom->getEnvelope(&x_env);
3433 16 : if (x_env.MaxX < sEnvelopeMethod.MinX ||
3434 16 : x_env.MaxY < sEnvelopeMethod.MinY ||
3435 16 : sEnvelopeMethod.MaxX < x_env.MinX ||
3436 16 : sEnvelopeMethod.MaxY < x_env.MinY)
3437 : {
3438 0 : continue;
3439 : }
3440 : }
3441 : else
3442 : {
3443 0 : continue;
3444 : }
3445 : }
3446 :
3447 : // set up the filter for method layer
3448 16 : CPLErrorReset();
3449 : OGRGeometry *x_geom =
3450 16 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3451 16 : if (CPLGetLastErrorType() != CE_None)
3452 : {
3453 0 : if (!bSkipFailures)
3454 : {
3455 0 : ret = OGRERR_FAILURE;
3456 0 : goto done;
3457 : }
3458 : else
3459 : {
3460 0 : CPLErrorReset();
3461 0 : ret = OGRERR_NONE;
3462 : }
3463 : }
3464 16 : if (!x_geom)
3465 : {
3466 0 : continue;
3467 : }
3468 :
3469 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
3470 16 : if (bUsePreparedGeometries)
3471 : {
3472 16 : x_prepared_geom.reset(
3473 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
3474 16 : if (!x_prepared_geom)
3475 : {
3476 0 : goto done;
3477 : }
3478 : }
3479 :
3480 34 : for (auto &&y : pLayerMethod)
3481 : {
3482 18 : OGRGeometry *y_geom = y->GetGeometryRef();
3483 18 : if (!y_geom)
3484 4 : continue;
3485 0 : OGRGeometryUniquePtr z_geom;
3486 :
3487 18 : if (x_prepared_geom)
3488 : {
3489 18 : CPLErrorReset();
3490 18 : ret = OGRERR_NONE;
3491 18 : if (bPretestContainment &&
3492 0 : OGRPreparedGeometryContains(x_prepared_geom.get(),
3493 : OGRGeometry::ToHandle(y_geom)))
3494 : {
3495 0 : if (CPLGetLastErrorType() == CE_None)
3496 0 : z_geom.reset(y_geom->clone());
3497 : }
3498 18 : else if (!(OGRPreparedGeometryIntersects(
3499 : x_prepared_geom.get(),
3500 : OGRGeometry::ToHandle(y_geom))))
3501 : {
3502 0 : if (CPLGetLastErrorType() == CE_None)
3503 : {
3504 0 : continue;
3505 : }
3506 : }
3507 18 : if (CPLGetLastErrorType() != CE_None)
3508 : {
3509 0 : if (!bSkipFailures)
3510 : {
3511 0 : ret = OGRERR_FAILURE;
3512 0 : goto done;
3513 : }
3514 : else
3515 : {
3516 0 : CPLErrorReset();
3517 0 : ret = OGRERR_NONE;
3518 0 : continue;
3519 : }
3520 : }
3521 : }
3522 18 : if (!z_geom)
3523 : {
3524 18 : CPLErrorReset();
3525 18 : z_geom.reset(x_geom->Intersection(y_geom));
3526 18 : if (CPLGetLastErrorType() != CE_None || z_geom == nullptr)
3527 : {
3528 0 : if (!bSkipFailures)
3529 : {
3530 0 : ret = OGRERR_FAILURE;
3531 0 : goto done;
3532 : }
3533 : else
3534 : {
3535 0 : CPLErrorReset();
3536 0 : ret = OGRERR_NONE;
3537 0 : continue;
3538 : }
3539 : }
3540 36 : if (z_geom->IsEmpty() ||
3541 18 : (!bKeepLowerDimGeom &&
3542 7 : (x_geom->getDimension() == y_geom->getDimension() &&
3543 7 : z_geom->getDimension() < x_geom->getDimension())))
3544 : {
3545 4 : continue;
3546 : }
3547 : }
3548 14 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3549 14 : z->SetFieldsFrom(x.get(), mapInput);
3550 14 : z->SetFieldsFrom(y.get(), mapMethod);
3551 14 : if (bPromoteToMulti)
3552 3 : z_geom.reset(promote_to_multi(z_geom.release()));
3553 14 : z->SetGeometryDirectly(z_geom.release());
3554 14 : ret = pLayerResult->CreateFeature(z.get());
3555 :
3556 14 : if (ret != OGRERR_NONE)
3557 : {
3558 0 : if (!bSkipFailures)
3559 : {
3560 0 : goto done;
3561 : }
3562 : else
3563 : {
3564 0 : CPLErrorReset();
3565 0 : ret = OGRERR_NONE;
3566 : }
3567 : }
3568 : }
3569 : }
3570 9 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
3571 : {
3572 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3573 0 : ret = OGRERR_FAILURE;
3574 0 : goto done;
3575 : }
3576 9 : done:
3577 : // release resources
3578 9 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3579 9 : if (pGeometryMethodFilter)
3580 0 : delete pGeometryMethodFilter;
3581 9 : if (mapInput)
3582 5 : VSIFree(mapInput);
3583 9 : if (mapMethod)
3584 5 : VSIFree(mapMethod);
3585 9 : return ret;
3586 : }
3587 :
3588 : /************************************************************************/
3589 : /* OGR_L_Intersection() */
3590 : /************************************************************************/
3591 : /**
3592 : * \brief Intersection of two layers.
3593 : *
3594 : * The result layer contains features whose geometries represent areas
3595 : * that are common between features in the input layer and in the
3596 : * method layer. The features in the result layer have attributes from
3597 : * both input and method layers. The schema of the result layer can be
3598 : * set by the user or, if it is empty, is initialized to contain all
3599 : * fields in the input and method layers.
3600 : *
3601 : * \note If the schema of the result is set by user and contains
3602 : * fields that have the same name as a field in input and in method
3603 : * layer, then the attribute in the result feature will get the value
3604 : * from the feature of the method layer.
3605 : *
3606 : * \note For best performance use the minimum amount of features in
3607 : * the method layer and copy it into a memory layer.
3608 : *
3609 : * \note This method relies on GEOS support. Do not use unless the
3610 : * GEOS support is compiled in.
3611 : *
3612 : * The recognized list of options is :
3613 : * <ul>
3614 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3615 : * feature could not be inserted or a GEOS call failed.
3616 : * </li>
3617 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3618 : * into MultiPolygons, LineStrings to MultiLineStrings or
3619 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
3620 : * </li>
3621 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3622 : * will be created from the fields of the input layer.
3623 : * </li>
3624 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3625 : * will be created from the fields of the method layer.
3626 : * </li>
3627 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3628 : * geometries to pretest intersection of features of method layer
3629 : * with features of this layer.
3630 : * </li>
3631 : * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
3632 : * containment of features of method layer within the features of
3633 : * this layer. This will speed up the method significantly in some
3634 : * cases. Requires that the prepared geometries are in effect.
3635 : * </li>
3636 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3637 : * result features with lower dimension geometry that would
3638 : * otherwise be added to the result layer. The default is YES, to add
3639 : * features with lower dimension geometry, but only if the result layer
3640 : * has an unknown geometry type.
3641 : * </li>
3642 : * </ul>
3643 : *
3644 : * This function is the same as the C++ method OGRLayer::Intersection().
3645 : *
3646 : * @param pLayerInput the input layer. Should not be NULL.
3647 : *
3648 : * @param pLayerMethod the method layer. Should not be NULL.
3649 : *
3650 : * @param pLayerResult the layer where the features resulting from the
3651 : * operation are inserted. Should not be NULL. See above the note
3652 : * about the schema.
3653 : *
3654 : * @param papszOptions NULL terminated list of options (may be NULL).
3655 : *
3656 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3657 : * reporting progress or NULL.
3658 : *
3659 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3660 : *
3661 : * @return an error code if there was an error or the execution was
3662 : * interrupted, OGRERR_NONE otherwise.
3663 : *
3664 : * @note The first geometry field is always used.
3665 : *
3666 : * @since OGR 1.10
3667 : */
3668 :
3669 8 : OGRErr OGR_L_Intersection(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
3670 : OGRLayerH pLayerResult, char **papszOptions,
3671 : GDALProgressFunc pfnProgress, void *pProgressArg)
3672 :
3673 : {
3674 8 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE);
3675 8 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Intersection",
3676 : OGRERR_INVALID_HANDLE);
3677 8 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Intersection",
3678 : OGRERR_INVALID_HANDLE);
3679 :
3680 : return OGRLayer::FromHandle(pLayerInput)
3681 8 : ->Intersection(OGRLayer::FromHandle(pLayerMethod),
3682 : OGRLayer::FromHandle(pLayerResult), papszOptions,
3683 8 : pfnProgress, pProgressArg);
3684 : }
3685 :
3686 : /************************************************************************/
3687 : /* Union() */
3688 : /************************************************************************/
3689 :
3690 : /**
3691 : * \brief Union of two layers.
3692 : *
3693 : * The result layer contains features whose geometries represent areas
3694 : * that are either in the input layer, in the method layer, or in
3695 : * both. The features in the result layer have attributes from both
3696 : * input and method layers. For features which represent areas that
3697 : * are only in the input or in the method layer the respective
3698 : * attributes have undefined values. The schema of the result layer
3699 : * can be set by the user or, if it is empty, is initialized to
3700 : * contain all fields in the input and method layers.
3701 : *
3702 : * \note If the schema of the result is set by user and contains
3703 : * fields that have the same name as a field in input and in method
3704 : * layer, then the attribute in the result feature will get the value
3705 : * from the feature of the method layer (even if it is undefined).
3706 : *
3707 : * \note For best performance use the minimum amount of features in
3708 : * the method layer and copy it into a memory layer.
3709 : *
3710 : * \note This method relies on GEOS support. Do not use unless the
3711 : * GEOS support is compiled in.
3712 : *
3713 : * The recognized list of options is :
3714 : * <ul>
3715 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3716 : * feature could not be inserted or a GEOS call failed.
3717 : * </li>
3718 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3719 : * into MultiPolygons, LineStrings to MultiLineStrings or
3720 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
3721 : * </li>
3722 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3723 : * will be created from the fields of the input layer.
3724 : * </li>
3725 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3726 : * will be created from the fields of the method layer.
3727 : * </li>
3728 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3729 : * geometries to pretest intersection of features of method layer
3730 : * with features of this layer.
3731 : * </li>
3732 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3733 : * result features with lower dimension geometry that would
3734 : * otherwise be added to the result layer. The default is YES, to add
3735 : * features with lower dimension geometry, but only if the result layer
3736 : * has an unknown geometry type.
3737 : * </li>
3738 : * </ul>
3739 : *
3740 : * This method is the same as the C function OGR_L_Union().
3741 : *
3742 : * @param pLayerMethod the method layer. Should not be NULL.
3743 : *
3744 : * @param pLayerResult the layer where the features resulting from the
3745 : * operation are inserted. Should not be NULL. See above the note
3746 : * about the schema.
3747 : *
3748 : * @param papszOptions NULL terminated list of options (may be NULL).
3749 : *
3750 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3751 : * reporting progress or NULL.
3752 : *
3753 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3754 : *
3755 : * @return an error code if there was an error or the execution was
3756 : * interrupted, OGRERR_NONE otherwise.
3757 : *
3758 : * @note The first geometry field is always used.
3759 : *
3760 : * @since OGR 1.10
3761 : */
3762 :
3763 18 : OGRErr OGRLayer::Union(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
3764 : char **papszOptions, GDALProgressFunc pfnProgress,
3765 : void *pProgressArg)
3766 : {
3767 18 : OGRErr ret = OGRERR_NONE;
3768 18 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
3769 18 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3770 18 : OGRFeatureDefn *poDefnResult = nullptr;
3771 18 : OGRGeometry *pGeometryMethodFilter = nullptr;
3772 18 : OGRGeometry *pGeometryInputFilter = nullptr;
3773 18 : int *mapInput = nullptr;
3774 18 : int *mapMethod = nullptr;
3775 : double progress_max =
3776 18 : static_cast<double>(GetFeatureCount(FALSE)) +
3777 18 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
3778 18 : double progress_counter = 0;
3779 18 : double progress_ticker = 0;
3780 : const bool bSkipFailures =
3781 18 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3782 18 : const bool bPromoteToMulti = CPLTestBool(
3783 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3784 18 : const bool bUsePreparedGeometries = CPLTestBool(
3785 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
3786 18 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
3787 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
3788 :
3789 : // check for GEOS
3790 18 : if (!OGRGeometryFactory::haveGEOS())
3791 : {
3792 0 : CPLError(CE_Failure, CPLE_AppDefined,
3793 : "OGRLayer::Union() requires GEOS support");
3794 0 : return OGRERR_UNSUPPORTED_OPERATION;
3795 : }
3796 :
3797 : // get resources
3798 18 : ret = clone_spatial_filter(this, &pGeometryInputFilter);
3799 18 : if (ret != OGRERR_NONE)
3800 0 : goto done;
3801 18 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3802 18 : if (ret != OGRERR_NONE)
3803 0 : goto done;
3804 18 : ret = create_field_map(poDefnInput, &mapInput);
3805 18 : if (ret != OGRERR_NONE)
3806 0 : goto done;
3807 18 : ret = create_field_map(poDefnMethod, &mapMethod);
3808 18 : if (ret != OGRERR_NONE)
3809 0 : goto done;
3810 18 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
3811 : mapMethod, true, papszOptions);
3812 18 : if (ret != OGRERR_NONE)
3813 0 : goto done;
3814 18 : poDefnResult = pLayerResult->GetLayerDefn();
3815 18 : if (bKeepLowerDimGeom)
3816 : {
3817 : // require that the result layer is of geom type unknown
3818 16 : if (pLayerResult->GetGeomType() != wkbUnknown)
3819 : {
3820 11 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
3821 : "since the result layer does not allow it.");
3822 11 : bKeepLowerDimGeom = FALSE;
3823 : }
3824 : }
3825 :
3826 : // add features based on input layer
3827 133 : for (auto &&x : this)
3828 : {
3829 :
3830 115 : if (pfnProgress)
3831 : {
3832 2 : double p = progress_counter / progress_max;
3833 2 : if (p > progress_ticker)
3834 : {
3835 1 : if (!pfnProgress(p, "", pProgressArg))
3836 : {
3837 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3838 0 : ret = OGRERR_FAILURE;
3839 0 : goto done;
3840 : }
3841 : }
3842 2 : progress_counter += 1.0;
3843 : }
3844 :
3845 : // set up the filter on method layer
3846 115 : CPLErrorReset();
3847 : OGRGeometry *x_geom =
3848 115 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3849 115 : if (CPLGetLastErrorType() != CE_None)
3850 : {
3851 0 : if (!bSkipFailures)
3852 : {
3853 0 : ret = OGRERR_FAILURE;
3854 0 : goto done;
3855 : }
3856 : else
3857 : {
3858 0 : CPLErrorReset();
3859 0 : ret = OGRERR_NONE;
3860 : }
3861 : }
3862 115 : if (!x_geom)
3863 : {
3864 0 : continue;
3865 : }
3866 :
3867 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
3868 115 : if (bUsePreparedGeometries)
3869 : {
3870 115 : x_prepared_geom.reset(
3871 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
3872 115 : if (!x_prepared_geom)
3873 : {
3874 0 : goto done;
3875 : }
3876 : }
3877 :
3878 : OGRGeometryUniquePtr x_geom_diff(
3879 : x_geom
3880 115 : ->clone()); // this will be the geometry of the result feature
3881 631 : for (auto &&y : pLayerMethod)
3882 : {
3883 516 : OGRGeometry *y_geom = y->GetGeometryRef();
3884 516 : if (!y_geom)
3885 : {
3886 0 : continue;
3887 : }
3888 :
3889 516 : CPLErrorReset();
3890 1032 : if (x_prepared_geom &&
3891 516 : !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
3892 516 : OGRGeometry::ToHandle(y_geom))))
3893 : {
3894 0 : if (CPLGetLastErrorType() == CE_None)
3895 : {
3896 0 : continue;
3897 : }
3898 : }
3899 516 : if (CPLGetLastErrorType() != CE_None)
3900 : {
3901 0 : if (!bSkipFailures)
3902 : {
3903 0 : ret = OGRERR_FAILURE;
3904 0 : goto done;
3905 : }
3906 : else
3907 : {
3908 0 : CPLErrorReset();
3909 0 : ret = OGRERR_NONE;
3910 : }
3911 : }
3912 :
3913 516 : CPLErrorReset();
3914 516 : OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
3915 516 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
3916 : {
3917 0 : if (!bSkipFailures)
3918 : {
3919 0 : ret = OGRERR_FAILURE;
3920 0 : goto done;
3921 : }
3922 : else
3923 : {
3924 0 : CPLErrorReset();
3925 0 : ret = OGRERR_NONE;
3926 0 : continue;
3927 : }
3928 : }
3929 1032 : if (poIntersection->IsEmpty() ||
3930 516 : (!bKeepLowerDimGeom &&
3931 507 : (x_geom->getDimension() == y_geom->getDimension() &&
3932 507 : poIntersection->getDimension() < x_geom->getDimension())))
3933 : {
3934 : // ok
3935 : }
3936 : else
3937 : {
3938 112 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3939 112 : z->SetFieldsFrom(x.get(), mapInput);
3940 112 : z->SetFieldsFrom(y.get(), mapMethod);
3941 112 : if (bPromoteToMulti)
3942 3 : poIntersection.reset(
3943 : promote_to_multi(poIntersection.release()));
3944 112 : z->SetGeometryDirectly(poIntersection.release());
3945 :
3946 112 : if (x_geom_diff)
3947 : {
3948 112 : CPLErrorReset();
3949 : OGRGeometryUniquePtr x_geom_diff_new(
3950 112 : x_geom_diff->Difference(y_geom));
3951 224 : if (CPLGetLastErrorType() != CE_None ||
3952 112 : x_geom_diff_new == nullptr)
3953 : {
3954 0 : if (!bSkipFailures)
3955 : {
3956 0 : ret = OGRERR_FAILURE;
3957 0 : goto done;
3958 : }
3959 : else
3960 : {
3961 0 : CPLErrorReset();
3962 : }
3963 : }
3964 : else
3965 : {
3966 112 : x_geom_diff.swap(x_geom_diff_new);
3967 : }
3968 : }
3969 :
3970 112 : ret = pLayerResult->CreateFeature(z.get());
3971 112 : if (ret != OGRERR_NONE)
3972 : {
3973 0 : if (!bSkipFailures)
3974 : {
3975 0 : goto done;
3976 : }
3977 : else
3978 : {
3979 0 : CPLErrorReset();
3980 0 : ret = OGRERR_NONE;
3981 : }
3982 : }
3983 : }
3984 : }
3985 115 : x_prepared_geom.reset();
3986 :
3987 115 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
3988 : {
3989 : // ok
3990 : }
3991 : else
3992 : {
3993 12 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3994 12 : z->SetFieldsFrom(x.get(), mapInput);
3995 12 : if (bPromoteToMulti)
3996 3 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
3997 12 : z->SetGeometryDirectly(x_geom_diff.release());
3998 12 : ret = pLayerResult->CreateFeature(z.get());
3999 12 : if (ret != OGRERR_NONE)
4000 : {
4001 0 : if (!bSkipFailures)
4002 : {
4003 0 : goto done;
4004 : }
4005 : else
4006 : {
4007 0 : CPLErrorReset();
4008 0 : ret = OGRERR_NONE;
4009 : }
4010 : }
4011 : }
4012 : }
4013 :
4014 : // restore filter on method layer and add features based on it
4015 18 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4016 130 : for (auto &&x : pLayerMethod)
4017 : {
4018 :
4019 112 : if (pfnProgress)
4020 : {
4021 1 : double p = progress_counter / progress_max;
4022 1 : if (p > progress_ticker)
4023 : {
4024 1 : if (!pfnProgress(p, "", pProgressArg))
4025 : {
4026 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4027 0 : ret = OGRERR_FAILURE;
4028 0 : goto done;
4029 : }
4030 : }
4031 1 : progress_counter += 1.0;
4032 : }
4033 :
4034 : // set up the filter on input layer
4035 112 : CPLErrorReset();
4036 : OGRGeometry *x_geom =
4037 112 : set_filter_from(this, pGeometryInputFilter, x.get());
4038 112 : if (CPLGetLastErrorType() != CE_None)
4039 : {
4040 0 : if (!bSkipFailures)
4041 : {
4042 0 : ret = OGRERR_FAILURE;
4043 0 : goto done;
4044 : }
4045 : else
4046 : {
4047 0 : CPLErrorReset();
4048 0 : ret = OGRERR_NONE;
4049 : }
4050 : }
4051 112 : if (!x_geom)
4052 : {
4053 0 : continue;
4054 : }
4055 :
4056 : OGRGeometryUniquePtr x_geom_diff(
4057 : x_geom
4058 112 : ->clone()); // this will be the geometry of the result feature
4059 628 : for (auto &&y : this)
4060 : {
4061 516 : OGRGeometry *y_geom = y->GetGeometryRef();
4062 516 : if (!y_geom)
4063 : {
4064 0 : continue;
4065 : }
4066 :
4067 516 : if (x_geom_diff)
4068 : {
4069 516 : CPLErrorReset();
4070 : OGRGeometryUniquePtr x_geom_diff_new(
4071 516 : x_geom_diff->Difference(y_geom));
4072 1032 : if (CPLGetLastErrorType() != CE_None ||
4073 516 : x_geom_diff_new == nullptr)
4074 : {
4075 0 : if (!bSkipFailures)
4076 : {
4077 0 : ret = OGRERR_FAILURE;
4078 0 : goto done;
4079 : }
4080 : else
4081 : {
4082 0 : CPLErrorReset();
4083 0 : ret = OGRERR_NONE;
4084 : }
4085 : }
4086 : else
4087 : {
4088 516 : x_geom_diff.swap(x_geom_diff_new);
4089 : }
4090 : }
4091 : }
4092 :
4093 112 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
4094 : {
4095 : // ok
4096 : }
4097 : else
4098 : {
4099 8 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4100 8 : z->SetFieldsFrom(x.get(), mapMethod);
4101 8 : if (bPromoteToMulti)
4102 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
4103 8 : z->SetGeometryDirectly(x_geom_diff.release());
4104 8 : ret = pLayerResult->CreateFeature(z.get());
4105 8 : if (ret != OGRERR_NONE)
4106 : {
4107 0 : if (!bSkipFailures)
4108 : {
4109 0 : goto done;
4110 : }
4111 : else
4112 : {
4113 0 : CPLErrorReset();
4114 0 : ret = OGRERR_NONE;
4115 : }
4116 : }
4117 : }
4118 : }
4119 18 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4120 : {
4121 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4122 0 : ret = OGRERR_FAILURE;
4123 0 : goto done;
4124 : }
4125 18 : done:
4126 : // release resources
4127 18 : SetSpatialFilter(pGeometryInputFilter);
4128 18 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4129 18 : if (pGeometryMethodFilter)
4130 0 : delete pGeometryMethodFilter;
4131 18 : if (pGeometryInputFilter)
4132 0 : delete pGeometryInputFilter;
4133 18 : if (mapInput)
4134 15 : VSIFree(mapInput);
4135 18 : if (mapMethod)
4136 14 : VSIFree(mapMethod);
4137 18 : return ret;
4138 : }
4139 :
4140 : /************************************************************************/
4141 : /* OGR_L_Union() */
4142 : /************************************************************************/
4143 :
4144 : /**
4145 : * \brief Union of two layers.
4146 : *
4147 : * The result layer contains features whose geometries represent areas
4148 : * that are in either in the input layer, in the method layer, or in
4149 : * both. The features in the result layer have attributes from both
4150 : * input and method layers. For features which represent areas that
4151 : * are only in the input or in the method layer the respective
4152 : * attributes have undefined values. The schema of the result layer
4153 : * can be set by the user or, if it is empty, is initialized to
4154 : * contain all fields in the input and method layers.
4155 : *
4156 : * \note If the schema of the result is set by user and contains
4157 : * fields that have the same name as a field in input and in method
4158 : * layer, then the attribute in the result feature will get the value
4159 : * from the feature of the method layer (even if it is undefined).
4160 : *
4161 : * \note For best performance use the minimum amount of features in
4162 : * the method layer and copy it into a memory layer.
4163 : *
4164 : * \note This method relies on GEOS support. Do not use unless the
4165 : * GEOS support is compiled in.
4166 : *
4167 : * The recognized list of options is :
4168 : * <ul>
4169 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4170 : * feature could not be inserted or a GEOS call failed.
4171 : * </li>
4172 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4173 : * into MultiPolygons, LineStrings to MultiLineStrings or
4174 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4175 : * </li>
4176 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4177 : * will be created from the fields of the input layer.
4178 : * </li>
4179 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4180 : * will be created from the fields of the method layer.
4181 : * </li>
4182 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
4183 : * geometries to pretest intersection of features of method layer
4184 : * with features of this layer.
4185 : * </li>
4186 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
4187 : * result features with lower dimension geometry that would
4188 : * otherwise be added to the result layer. The default is YES, to add
4189 : * features with lower dimension geometry, but only if the result layer
4190 : * has an unknown geometry type.
4191 : * </li>
4192 : * </ul>
4193 : *
4194 : * This function is the same as the C++ method OGRLayer::Union().
4195 : *
4196 : * @param pLayerInput the input layer. Should not be NULL.
4197 : *
4198 : * @param pLayerMethod the method layer. Should not be NULL.
4199 : *
4200 : * @param pLayerResult the layer where the features resulting from the
4201 : * operation are inserted. Should not be NULL. See above the note
4202 : * about the schema.
4203 : *
4204 : * @param papszOptions NULL terminated list of options (may be NULL).
4205 : *
4206 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4207 : * reporting progress or NULL.
4208 : *
4209 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4210 : *
4211 : * @return an error code if there was an error or the execution was
4212 : * interrupted, OGRERR_NONE otherwise.
4213 : *
4214 : * @note The first geometry field is always used.
4215 : *
4216 : * @since OGR 1.10
4217 : */
4218 :
4219 7 : OGRErr OGR_L_Union(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
4220 : OGRLayerH pLayerResult, char **papszOptions,
4221 : GDALProgressFunc pfnProgress, void *pProgressArg)
4222 :
4223 : {
4224 7 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE);
4225 7 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE);
4226 7 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE);
4227 :
4228 : return OGRLayer::FromHandle(pLayerInput)
4229 7 : ->Union(OGRLayer::FromHandle(pLayerMethod),
4230 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
4231 7 : pProgressArg);
4232 : }
4233 :
4234 : /************************************************************************/
4235 : /* SymDifference() */
4236 : /************************************************************************/
4237 :
4238 : /**
4239 : * \brief Symmetrical difference of two layers.
4240 : *
4241 : * The result layer contains features whose geometries represent areas
4242 : * that are in either in the input layer or in the method layer but
4243 : * not in both. The features in the result layer have attributes from
4244 : * both input and method layers. For features which represent areas
4245 : * that are only in the input or in the method layer the respective
4246 : * attributes have undefined values. The schema of the result layer
4247 : * can be set by the user or, if it is empty, is initialized to
4248 : * contain all fields in the input and method layers.
4249 : *
4250 : * \note If the schema of the result is set by user and contains
4251 : * fields that have the same name as a field in input and in method
4252 : * layer, then the attribute in the result feature will get the value
4253 : * from the feature of the method layer (even if it is undefined).
4254 : *
4255 : * \note For best performance use the minimum amount of features in
4256 : * the method layer and copy it into a memory layer.
4257 : *
4258 : * \note This method relies on GEOS support. Do not use unless the
4259 : * GEOS support is compiled in.
4260 : *
4261 : * The recognized list of options is :
4262 : * <ul>
4263 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4264 : * feature could not be inserted or a GEOS call failed.
4265 : * </li>
4266 : * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
4267 : * into MultiPolygons, or LineStrings to MultiLineStrings.
4268 : * </li>
4269 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4270 : * will be created from the fields of the input layer.
4271 : * </li>
4272 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4273 : * will be created from the fields of the method layer.
4274 : * </li>
4275 : * </ul>
4276 : *
4277 : * This method is the same as the C function OGR_L_SymDifference().
4278 : *
4279 : * @param pLayerMethod the method layer. Should not be NULL.
4280 : *
4281 : * @param pLayerResult the layer where the features resulting from the
4282 : * operation are inserted. Should not be NULL. See above the note
4283 : * about the schema.
4284 : *
4285 : * @param papszOptions NULL terminated list of options (may be NULL).
4286 : *
4287 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4288 : * reporting progress or NULL.
4289 : *
4290 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4291 : *
4292 : * @return an error code if there was an error or the execution was
4293 : * interrupted, OGRERR_NONE otherwise.
4294 : *
4295 : * @note The first geometry field is always used.
4296 : *
4297 : * @since OGR 1.10
4298 : */
4299 :
4300 5 : OGRErr OGRLayer::SymDifference(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
4301 : char **papszOptions,
4302 : GDALProgressFunc pfnProgress, void *pProgressArg)
4303 : {
4304 5 : OGRErr ret = OGRERR_NONE;
4305 5 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
4306 5 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
4307 5 : OGRFeatureDefn *poDefnResult = nullptr;
4308 5 : OGRGeometry *pGeometryMethodFilter = nullptr;
4309 5 : OGRGeometry *pGeometryInputFilter = nullptr;
4310 5 : int *mapInput = nullptr;
4311 5 : int *mapMethod = nullptr;
4312 : double progress_max =
4313 5 : static_cast<double>(GetFeatureCount(FALSE)) +
4314 5 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
4315 5 : double progress_counter = 0;
4316 5 : double progress_ticker = 0;
4317 : const bool bSkipFailures =
4318 5 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4319 5 : const bool bPromoteToMulti = CPLTestBool(
4320 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4321 :
4322 : // check for GEOS
4323 5 : if (!OGRGeometryFactory::haveGEOS())
4324 : {
4325 0 : CPLError(CE_Failure, CPLE_AppDefined,
4326 : "OGRLayer::SymDifference() requires GEOS support");
4327 0 : return OGRERR_UNSUPPORTED_OPERATION;
4328 : }
4329 :
4330 : // get resources
4331 5 : ret = clone_spatial_filter(this, &pGeometryInputFilter);
4332 5 : if (ret != OGRERR_NONE)
4333 0 : goto done;
4334 5 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4335 5 : if (ret != OGRERR_NONE)
4336 0 : goto done;
4337 5 : ret = create_field_map(poDefnInput, &mapInput);
4338 5 : if (ret != OGRERR_NONE)
4339 0 : goto done;
4340 5 : ret = create_field_map(poDefnMethod, &mapMethod);
4341 5 : if (ret != OGRERR_NONE)
4342 0 : goto done;
4343 5 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
4344 : mapMethod, true, papszOptions);
4345 5 : if (ret != OGRERR_NONE)
4346 0 : goto done;
4347 5 : poDefnResult = pLayerResult->GetLayerDefn();
4348 :
4349 : // add features based on input layer
4350 15 : for (auto &&x : this)
4351 : {
4352 :
4353 10 : if (pfnProgress)
4354 : {
4355 2 : double p = progress_counter / progress_max;
4356 2 : if (p > progress_ticker)
4357 : {
4358 1 : if (!pfnProgress(p, "", pProgressArg))
4359 : {
4360 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4361 0 : ret = OGRERR_FAILURE;
4362 0 : goto done;
4363 : }
4364 : }
4365 2 : progress_counter += 1.0;
4366 : }
4367 :
4368 : // set up the filter on method layer
4369 10 : CPLErrorReset();
4370 : OGRGeometry *x_geom =
4371 10 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
4372 10 : if (CPLGetLastErrorType() != CE_None)
4373 : {
4374 0 : if (!bSkipFailures)
4375 : {
4376 0 : ret = OGRERR_FAILURE;
4377 0 : goto done;
4378 : }
4379 : else
4380 : {
4381 0 : CPLErrorReset();
4382 0 : ret = OGRERR_NONE;
4383 : }
4384 : }
4385 10 : if (!x_geom)
4386 : {
4387 0 : continue;
4388 : }
4389 :
4390 : OGRGeometryUniquePtr geom(
4391 : x_geom
4392 10 : ->clone()); // this will be the geometry of the result feature
4393 18 : for (auto &&y : pLayerMethod)
4394 : {
4395 11 : OGRGeometry *y_geom = y->GetGeometryRef();
4396 11 : if (!y_geom)
4397 : {
4398 0 : continue;
4399 : }
4400 11 : if (geom)
4401 : {
4402 11 : CPLErrorReset();
4403 11 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
4404 11 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
4405 : {
4406 0 : if (!bSkipFailures)
4407 : {
4408 0 : ret = OGRERR_FAILURE;
4409 0 : goto done;
4410 : }
4411 : else
4412 : {
4413 0 : CPLErrorReset();
4414 0 : ret = OGRERR_NONE;
4415 : }
4416 : }
4417 : else
4418 : {
4419 11 : geom.swap(geom_new);
4420 : }
4421 : }
4422 11 : if (geom && geom->IsEmpty())
4423 3 : break;
4424 : }
4425 :
4426 10 : if (geom && !geom->IsEmpty())
4427 : {
4428 7 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4429 7 : z->SetFieldsFrom(x.get(), mapInput);
4430 7 : if (bPromoteToMulti)
4431 2 : geom.reset(promote_to_multi(geom.release()));
4432 7 : z->SetGeometryDirectly(geom.release());
4433 7 : ret = pLayerResult->CreateFeature(z.get());
4434 7 : if (ret != OGRERR_NONE)
4435 : {
4436 0 : if (!bSkipFailures)
4437 : {
4438 0 : goto done;
4439 : }
4440 : else
4441 : {
4442 0 : CPLErrorReset();
4443 0 : ret = OGRERR_NONE;
4444 : }
4445 : }
4446 : }
4447 : }
4448 :
4449 : // restore filter on method layer and add features based on it
4450 5 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4451 14 : for (auto &&x : pLayerMethod)
4452 : {
4453 :
4454 9 : if (pfnProgress)
4455 : {
4456 2 : double p = progress_counter / progress_max;
4457 2 : if (p > progress_ticker)
4458 : {
4459 2 : if (!pfnProgress(p, "", pProgressArg))
4460 : {
4461 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4462 0 : ret = OGRERR_FAILURE;
4463 0 : goto done;
4464 : }
4465 : }
4466 2 : progress_counter += 1.0;
4467 : }
4468 :
4469 : // set up the filter on input layer
4470 9 : CPLErrorReset();
4471 : OGRGeometry *x_geom =
4472 9 : set_filter_from(this, pGeometryInputFilter, x.get());
4473 9 : if (CPLGetLastErrorType() != CE_None)
4474 : {
4475 0 : if (!bSkipFailures)
4476 : {
4477 0 : ret = OGRERR_FAILURE;
4478 0 : goto done;
4479 : }
4480 : else
4481 : {
4482 0 : CPLErrorReset();
4483 0 : ret = OGRERR_NONE;
4484 : }
4485 : }
4486 9 : if (!x_geom)
4487 : {
4488 0 : continue;
4489 : }
4490 :
4491 : OGRGeometryUniquePtr geom(
4492 : x_geom
4493 9 : ->clone()); // this will be the geometry of the result feature
4494 17 : for (auto &&y : this)
4495 : {
4496 11 : OGRGeometry *y_geom = y->GetGeometryRef();
4497 11 : if (!y_geom)
4498 0 : continue;
4499 11 : if (geom)
4500 : {
4501 11 : CPLErrorReset();
4502 11 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
4503 11 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
4504 : {
4505 0 : if (!bSkipFailures)
4506 : {
4507 0 : ret = OGRERR_FAILURE;
4508 0 : goto done;
4509 : }
4510 : else
4511 : {
4512 0 : CPLErrorReset();
4513 0 : ret = OGRERR_NONE;
4514 : }
4515 : }
4516 : else
4517 : {
4518 11 : geom.swap(geom_new);
4519 : }
4520 : }
4521 11 : if (geom == nullptr || geom->IsEmpty())
4522 3 : break;
4523 : }
4524 :
4525 9 : if (geom && !geom->IsEmpty())
4526 : {
4527 6 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4528 6 : z->SetFieldsFrom(x.get(), mapMethod);
4529 6 : if (bPromoteToMulti)
4530 1 : geom.reset(promote_to_multi(geom.release()));
4531 6 : z->SetGeometryDirectly(geom.release());
4532 6 : ret = pLayerResult->CreateFeature(z.get());
4533 6 : if (ret != OGRERR_NONE)
4534 : {
4535 0 : if (!bSkipFailures)
4536 : {
4537 0 : goto done;
4538 : }
4539 : else
4540 : {
4541 0 : CPLErrorReset();
4542 0 : ret = OGRERR_NONE;
4543 : }
4544 : }
4545 : }
4546 : }
4547 5 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4548 : {
4549 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4550 0 : ret = OGRERR_FAILURE;
4551 0 : goto done;
4552 : }
4553 5 : done:
4554 : // release resources
4555 5 : SetSpatialFilter(pGeometryInputFilter);
4556 5 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4557 5 : if (pGeometryMethodFilter)
4558 0 : delete pGeometryMethodFilter;
4559 5 : if (pGeometryInputFilter)
4560 0 : delete pGeometryInputFilter;
4561 5 : if (mapInput)
4562 4 : VSIFree(mapInput);
4563 5 : if (mapMethod)
4564 4 : VSIFree(mapMethod);
4565 5 : return ret;
4566 : }
4567 :
4568 : /************************************************************************/
4569 : /* OGR_L_SymDifference() */
4570 : /************************************************************************/
4571 :
4572 : /**
4573 : * \brief Symmetrical difference of two layers.
4574 : *
4575 : * The result layer contains features whose geometries represent areas
4576 : * that are in either in the input layer or in the method layer but
4577 : * not in both. The features in the result layer have attributes from
4578 : * both input and method layers. For features which represent areas
4579 : * that are only in the input or in the method layer the respective
4580 : * attributes have undefined values. The schema of the result layer
4581 : * can be set by the user or, if it is empty, is initialized to
4582 : * contain all fields in the input and method layers.
4583 : *
4584 : * \note If the schema of the result is set by user and contains
4585 : * fields that have the same name as a field in input and in method
4586 : * layer, then the attribute in the result feature will get the value
4587 : * from the feature of the method layer (even if it is undefined).
4588 : *
4589 : * \note For best performance use the minimum amount of features in
4590 : * the method layer and copy it into a memory layer.
4591 : *
4592 : * \note This method relies on GEOS support. Do not use unless the
4593 : * GEOS support is compiled in.
4594 : *
4595 : * The recognized list of options is :
4596 : * <ul>
4597 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4598 : * feature could not be inserted or a GEOS call failed.
4599 : * </li>
4600 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4601 : * into MultiPolygons, LineStrings to MultiLineStrings or
4602 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4603 : * </li>
4604 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4605 : * will be created from the fields of the input layer.
4606 : * </li>
4607 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4608 : * will be created from the fields of the method layer.
4609 : * </li>
4610 : * </ul>
4611 : *
4612 : * This function is the same as the C++ method OGRLayer::SymDifference().
4613 : *
4614 : * @param pLayerInput the input layer. Should not be NULL.
4615 : *
4616 : * @param pLayerMethod the method layer. Should not be NULL.
4617 : *
4618 : * @param pLayerResult the layer where the features resulting from the
4619 : * operation are inserted. Should not be NULL. See above the note
4620 : * about the schema.
4621 : *
4622 : * @param papszOptions NULL terminated list of options (may be NULL).
4623 : *
4624 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4625 : * reporting progress or NULL.
4626 : *
4627 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4628 : *
4629 : * @return an error code if there was an error or the execution was
4630 : * interrupted, OGRERR_NONE otherwise.
4631 : *
4632 : * @note The first geometry field is always used.
4633 : *
4634 : * @since OGR 1.10
4635 : */
4636 :
4637 4 : OGRErr OGR_L_SymDifference(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
4638 : OGRLayerH pLayerResult, char **papszOptions,
4639 : GDALProgressFunc pfnProgress, void *pProgressArg)
4640 :
4641 : {
4642 4 : VALIDATE_POINTER1(pLayerInput, "OGR_L_SymDifference",
4643 : OGRERR_INVALID_HANDLE);
4644 4 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_SymDifference",
4645 : OGRERR_INVALID_HANDLE);
4646 4 : VALIDATE_POINTER1(pLayerResult, "OGR_L_SymDifference",
4647 : OGRERR_INVALID_HANDLE);
4648 :
4649 : return OGRLayer::FromHandle(pLayerInput)
4650 4 : ->SymDifference(OGRLayer::FromHandle(pLayerMethod),
4651 : OGRLayer::FromHandle(pLayerResult), papszOptions,
4652 4 : pfnProgress, pProgressArg);
4653 : }
4654 :
4655 : /************************************************************************/
4656 : /* Identity() */
4657 : /************************************************************************/
4658 :
4659 : /**
4660 : * \brief Identify the features of this layer with the ones from the
4661 : * identity layer.
4662 : *
4663 : * The result layer contains features whose geometries represent areas
4664 : * that are in the input layer. The features in the result layer have
4665 : * attributes from both input and method layers. The schema of the
4666 : * result layer can be set by the user or, if it is empty, is
4667 : * initialized to contain all fields in input and method layers.
4668 : *
4669 : * \note If the schema of the result is set by user and contains
4670 : * fields that have the same name as a field in input and in method
4671 : * layer, then the attribute in the result feature will get the value
4672 : * from the feature of the method layer (even if it is undefined).
4673 : *
4674 : * \note For best performance use the minimum amount of features in
4675 : * the method layer and copy it into a memory layer.
4676 : *
4677 : * \note This method relies on GEOS support. Do not use unless the
4678 : * GEOS support is compiled in.
4679 : *
4680 : * The recognized list of options is :
4681 : * <ul>
4682 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4683 : * feature could not be inserted or a GEOS call failed.
4684 : * </li>
4685 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4686 : * into MultiPolygons, LineStrings to MultiLineStrings or
4687 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4688 : * </li>
4689 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4690 : * will be created from the fields of the input layer.
4691 : * </li>
4692 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4693 : * will be created from the fields of the method layer.
4694 : * </li>
4695 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
4696 : * geometries to pretest intersection of features of method layer
4697 : * with features of this layer.
4698 : * </li>
4699 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
4700 : * result features with lower dimension geometry that would
4701 : * otherwise be added to the result layer. The default is YES, to add
4702 : * features with lower dimension geometry, but only if the result layer
4703 : * has an unknown geometry type.
4704 : * </li>
4705 : * </ul>
4706 : *
4707 : * This method is the same as the C function OGR_L_Identity().
4708 : *
4709 : * @param pLayerMethod the method layer. Should not be NULL.
4710 : *
4711 : * @param pLayerResult the layer where the features resulting from the
4712 : * operation are inserted. Should not be NULL. See above the note
4713 : * about the schema.
4714 : *
4715 : * @param papszOptions NULL terminated list of options (may be NULL).
4716 : *
4717 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4718 : * reporting progress or NULL.
4719 : *
4720 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4721 : *
4722 : * @return an error code if there was an error or the execution was
4723 : * interrupted, OGRERR_NONE otherwise.
4724 : *
4725 : * @note The first geometry field is always used.
4726 : *
4727 : * @since OGR 1.10
4728 : */
4729 :
4730 7 : OGRErr OGRLayer::Identity(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
4731 : char **papszOptions, GDALProgressFunc pfnProgress,
4732 : void *pProgressArg)
4733 : {
4734 7 : OGRErr ret = OGRERR_NONE;
4735 7 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
4736 7 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
4737 7 : OGRFeatureDefn *poDefnResult = nullptr;
4738 7 : OGRGeometry *pGeometryMethodFilter = nullptr;
4739 7 : int *mapInput = nullptr;
4740 7 : int *mapMethod = nullptr;
4741 7 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
4742 7 : double progress_counter = 0;
4743 7 : double progress_ticker = 0;
4744 : const bool bSkipFailures =
4745 7 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4746 7 : const bool bPromoteToMulti = CPLTestBool(
4747 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4748 7 : const bool bUsePreparedGeometries = CPLTestBool(
4749 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
4750 7 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
4751 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
4752 :
4753 : // check for GEOS
4754 7 : if (!OGRGeometryFactory::haveGEOS())
4755 : {
4756 0 : CPLError(CE_Failure, CPLE_AppDefined,
4757 : "OGRLayer::Identity() requires GEOS support");
4758 0 : return OGRERR_UNSUPPORTED_OPERATION;
4759 : }
4760 7 : if (bKeepLowerDimGeom)
4761 : {
4762 : // require that the result layer is of geom type unknown
4763 5 : if (pLayerResult->GetGeomType() != wkbUnknown)
4764 : {
4765 0 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
4766 : "since the result layer does not allow it.");
4767 0 : bKeepLowerDimGeom = FALSE;
4768 : }
4769 : }
4770 :
4771 : // get resources
4772 7 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4773 7 : if (ret != OGRERR_NONE)
4774 0 : goto done;
4775 7 : ret = create_field_map(poDefnInput, &mapInput);
4776 7 : if (ret != OGRERR_NONE)
4777 0 : goto done;
4778 7 : ret = create_field_map(poDefnMethod, &mapMethod);
4779 7 : if (ret != OGRERR_NONE)
4780 0 : goto done;
4781 7 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
4782 : mapMethod, true, papszOptions);
4783 7 : if (ret != OGRERR_NONE)
4784 0 : goto done;
4785 7 : poDefnResult = pLayerResult->GetLayerDefn();
4786 :
4787 : // split the features in input layer to the result layer
4788 21 : for (auto &&x : this)
4789 : {
4790 :
4791 14 : if (pfnProgress)
4792 : {
4793 2 : double p = progress_counter / progress_max;
4794 2 : if (p > progress_ticker)
4795 : {
4796 1 : if (!pfnProgress(p, "", pProgressArg))
4797 : {
4798 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4799 0 : ret = OGRERR_FAILURE;
4800 0 : goto done;
4801 : }
4802 : }
4803 2 : progress_counter += 1.0;
4804 : }
4805 :
4806 : // set up the filter on method layer
4807 14 : CPLErrorReset();
4808 : OGRGeometry *x_geom =
4809 14 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
4810 14 : if (CPLGetLastErrorType() != CE_None)
4811 : {
4812 0 : if (!bSkipFailures)
4813 : {
4814 0 : ret = OGRERR_FAILURE;
4815 0 : goto done;
4816 : }
4817 : else
4818 : {
4819 0 : CPLErrorReset();
4820 0 : ret = OGRERR_NONE;
4821 : }
4822 : }
4823 14 : if (!x_geom)
4824 : {
4825 0 : continue;
4826 : }
4827 :
4828 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
4829 14 : if (bUsePreparedGeometries)
4830 : {
4831 14 : x_prepared_geom.reset(
4832 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
4833 14 : if (!x_prepared_geom)
4834 : {
4835 0 : goto done;
4836 : }
4837 : }
4838 :
4839 : OGRGeometryUniquePtr x_geom_diff(
4840 : x_geom
4841 14 : ->clone()); // this will be the geometry of the result feature
4842 30 : for (auto &&y : pLayerMethod)
4843 : {
4844 16 : OGRGeometry *y_geom = y->GetGeometryRef();
4845 16 : if (!y_geom)
4846 0 : continue;
4847 :
4848 16 : CPLErrorReset();
4849 32 : if (x_prepared_geom &&
4850 16 : !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
4851 16 : OGRGeometry::ToHandle(y_geom))))
4852 : {
4853 0 : if (CPLGetLastErrorType() == CE_None)
4854 : {
4855 0 : continue;
4856 : }
4857 : }
4858 16 : if (CPLGetLastErrorType() != CE_None)
4859 : {
4860 0 : if (!bSkipFailures)
4861 : {
4862 0 : ret = OGRERR_FAILURE;
4863 0 : goto done;
4864 : }
4865 : else
4866 : {
4867 0 : CPLErrorReset();
4868 0 : ret = OGRERR_NONE;
4869 : }
4870 : }
4871 :
4872 16 : CPLErrorReset();
4873 16 : OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
4874 16 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
4875 : {
4876 0 : if (!bSkipFailures)
4877 : {
4878 0 : ret = OGRERR_FAILURE;
4879 0 : goto done;
4880 : }
4881 : else
4882 : {
4883 0 : CPLErrorReset();
4884 0 : ret = OGRERR_NONE;
4885 : }
4886 : }
4887 32 : else if (poIntersection->IsEmpty() ||
4888 16 : (!bKeepLowerDimGeom &&
4889 6 : (x_geom->getDimension() == y_geom->getDimension() &&
4890 6 : poIntersection->getDimension() <
4891 6 : x_geom->getDimension())))
4892 : {
4893 : /* ok*/
4894 : }
4895 : else
4896 : {
4897 12 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4898 12 : z->SetFieldsFrom(x.get(), mapInput);
4899 12 : z->SetFieldsFrom(y.get(), mapMethod);
4900 12 : if (bPromoteToMulti)
4901 2 : poIntersection.reset(
4902 : promote_to_multi(poIntersection.release()));
4903 12 : z->SetGeometryDirectly(poIntersection.release());
4904 12 : if (x_geom_diff)
4905 : {
4906 12 : CPLErrorReset();
4907 : OGRGeometryUniquePtr x_geom_diff_new(
4908 12 : x_geom_diff->Difference(y_geom));
4909 24 : if (CPLGetLastErrorType() != CE_None ||
4910 12 : x_geom_diff_new == nullptr)
4911 : {
4912 0 : if (!bSkipFailures)
4913 : {
4914 0 : ret = OGRERR_FAILURE;
4915 0 : goto done;
4916 : }
4917 : else
4918 : {
4919 0 : CPLErrorReset();
4920 : }
4921 : }
4922 : else
4923 : {
4924 12 : x_geom_diff.swap(x_geom_diff_new);
4925 : }
4926 : }
4927 12 : ret = pLayerResult->CreateFeature(z.get());
4928 12 : if (ret != OGRERR_NONE)
4929 : {
4930 0 : if (!bSkipFailures)
4931 : {
4932 0 : goto done;
4933 : }
4934 : else
4935 : {
4936 0 : CPLErrorReset();
4937 0 : ret = OGRERR_NONE;
4938 : }
4939 : }
4940 : }
4941 : }
4942 :
4943 14 : x_prepared_geom.reset();
4944 :
4945 14 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
4946 : {
4947 : /* ok */
4948 : }
4949 : else
4950 : {
4951 11 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4952 11 : z->SetFieldsFrom(x.get(), mapInput);
4953 11 : if (bPromoteToMulti)
4954 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
4955 11 : z->SetGeometryDirectly(x_geom_diff.release());
4956 11 : ret = pLayerResult->CreateFeature(z.get());
4957 11 : if (ret != OGRERR_NONE)
4958 : {
4959 0 : if (!bSkipFailures)
4960 : {
4961 0 : goto done;
4962 : }
4963 : else
4964 : {
4965 0 : CPLErrorReset();
4966 0 : ret = OGRERR_NONE;
4967 : }
4968 : }
4969 : }
4970 : }
4971 7 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4972 : {
4973 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4974 0 : ret = OGRERR_FAILURE;
4975 0 : goto done;
4976 : }
4977 7 : done:
4978 : // release resources
4979 7 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4980 7 : if (pGeometryMethodFilter)
4981 0 : delete pGeometryMethodFilter;
4982 7 : if (mapInput)
4983 4 : VSIFree(mapInput);
4984 7 : if (mapMethod)
4985 4 : VSIFree(mapMethod);
4986 7 : return ret;
4987 : }
4988 :
4989 : /************************************************************************/
4990 : /* OGR_L_Identity() */
4991 : /************************************************************************/
4992 :
4993 : /**
4994 : * \brief Identify the features of this layer with the ones from the
4995 : * identity layer.
4996 : *
4997 : * The result layer contains features whose geometries represent areas
4998 : * that are in the input layer. The features in the result layer have
4999 : * attributes from both input and method layers. The schema of the
5000 : * result layer can be set by the user or, if it is empty, is
5001 : * initialized to contain all fields in input and method layers.
5002 : *
5003 : * \note If the schema of the result is set by user and contains
5004 : * fields that have the same name as a field in input and in method
5005 : * layer, then the attribute in the result feature will get the value
5006 : * from the feature of the method layer (even if it is undefined).
5007 : *
5008 : * \note For best performance use the minimum amount of features in
5009 : * the method layer and copy it into a memory layer.
5010 : *
5011 : * \note This method relies on GEOS support. Do not use unless the
5012 : * GEOS support is compiled in.
5013 : *
5014 : * The recognized list of options is :
5015 : * <ul>
5016 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5017 : * feature could not be inserted or a GEOS call failed.
5018 : * </li>
5019 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5020 : * into MultiPolygons, LineStrings to MultiLineStrings or
5021 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5022 : * </li>
5023 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5024 : * will be created from the fields of the input layer.
5025 : * </li>
5026 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5027 : * will be created from the fields of the method layer.
5028 : * </li>
5029 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
5030 : * geometries to pretest intersection of features of method layer
5031 : * with features of this layer.
5032 : * </li>
5033 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
5034 : * result features with lower dimension geometry that would
5035 : * otherwise be added to the result layer. The default is YES, to add
5036 : * features with lower dimension geometry, but only if the result layer
5037 : * has an unknown geometry type.
5038 : * </li>
5039 : * </ul>
5040 : *
5041 : * This function is the same as the C++ method OGRLayer::Identity().
5042 : *
5043 : * @param pLayerInput the input layer. Should not be NULL.
5044 : *
5045 : * @param pLayerMethod the method layer. Should not be NULL.
5046 : *
5047 : * @param pLayerResult the layer where the features resulting from the
5048 : * operation are inserted. Should not be NULL. See above the note
5049 : * about the schema.
5050 : *
5051 : * @param papszOptions NULL terminated list of options (may be NULL).
5052 : *
5053 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5054 : * reporting progress or NULL.
5055 : *
5056 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5057 : *
5058 : * @return an error code if there was an error or the execution was
5059 : * interrupted, OGRERR_NONE otherwise.
5060 : *
5061 : * @note The first geometry field is always used.
5062 : *
5063 : * @since OGR 1.10
5064 : */
5065 :
5066 6 : OGRErr OGR_L_Identity(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5067 : OGRLayerH pLayerResult, char **papszOptions,
5068 : GDALProgressFunc pfnProgress, void *pProgressArg)
5069 :
5070 : {
5071 6 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
5072 6 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
5073 6 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
5074 :
5075 : return OGRLayer::FromHandle(pLayerInput)
5076 6 : ->Identity(OGRLayer::FromHandle(pLayerMethod),
5077 : OGRLayer::FromHandle(pLayerResult), papszOptions,
5078 6 : pfnProgress, pProgressArg);
5079 : }
5080 :
5081 : /************************************************************************/
5082 : /* Update() */
5083 : /************************************************************************/
5084 :
5085 : /**
5086 : * \brief Update this layer with features from the update layer.
5087 : *
5088 : * The result layer contains features whose geometries represent areas
5089 : * that are either in the input layer or in the method layer. The
5090 : * features in the result layer have areas of the features of the
5091 : * method layer or those ares of the features of the input layer that
5092 : * are not covered by the method layer. The features of the result
5093 : * layer get their attributes from the input layer. The schema of the
5094 : * result layer can be set by the user or, if it is empty, is
5095 : * initialized to contain all fields in the input layer.
5096 : *
5097 : * \note If the schema of the result is set by user and contains
5098 : * fields that have the same name as a field in the method layer, then
5099 : * the attribute in the result feature the originates from the method
5100 : * layer will get the value from the feature of the method layer.
5101 : *
5102 : * \note For best performance use the minimum amount of features in
5103 : * the method layer and copy it into a memory layer.
5104 : *
5105 : * \note This method relies on GEOS support. Do not use unless the
5106 : * GEOS support is compiled in.
5107 : *
5108 : * The recognized list of options is :
5109 : * <ul>
5110 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5111 : * feature could not be inserted or a GEOS call failed.
5112 : * </li>
5113 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5114 : * into MultiPolygons, LineStrings to MultiLineStrings or
5115 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5116 : * </li>
5117 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5118 : * will be created from the fields of the input layer.
5119 : * </li>
5120 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5121 : * will be created from the fields of the method layer.
5122 : * </li>
5123 : * </ul>
5124 : *
5125 : * This method is the same as the C function OGR_L_Update().
5126 : *
5127 : * @param pLayerMethod the method layer. Should not be NULL.
5128 : *
5129 : * @param pLayerResult the layer where the features resulting from the
5130 : * operation are inserted. Should not be NULL. See above the note
5131 : * about the schema.
5132 : *
5133 : * @param papszOptions NULL terminated list of options (may be NULL).
5134 : *
5135 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5136 : * reporting progress or NULL.
5137 : *
5138 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5139 : *
5140 : * @return an error code if there was an error or the execution was
5141 : * interrupted, OGRERR_NONE otherwise.
5142 : *
5143 : * @note The first geometry field is always used.
5144 : *
5145 : * @since OGR 1.10
5146 : */
5147 :
5148 6 : OGRErr OGRLayer::Update(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5149 : char **papszOptions, GDALProgressFunc pfnProgress,
5150 : void *pProgressArg)
5151 : {
5152 6 : OGRErr ret = OGRERR_NONE;
5153 6 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
5154 6 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
5155 6 : OGRFeatureDefn *poDefnResult = nullptr;
5156 6 : OGRGeometry *pGeometryMethodFilter = nullptr;
5157 6 : int *mapInput = nullptr;
5158 6 : int *mapMethod = nullptr;
5159 : double progress_max =
5160 6 : static_cast<double>(GetFeatureCount(FALSE)) +
5161 6 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
5162 6 : double progress_counter = 0;
5163 6 : double progress_ticker = 0;
5164 : const bool bSkipFailures =
5165 6 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5166 6 : const bool bPromoteToMulti = CPLTestBool(
5167 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5168 :
5169 : // check for GEOS
5170 6 : if (!OGRGeometryFactory::haveGEOS())
5171 : {
5172 0 : CPLError(CE_Failure, CPLE_AppDefined,
5173 : "OGRLayer::Update() requires GEOS support");
5174 0 : return OGRERR_UNSUPPORTED_OPERATION;
5175 : }
5176 :
5177 : // get resources
5178 6 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5179 6 : if (ret != OGRERR_NONE)
5180 0 : goto done;
5181 6 : ret = create_field_map(poDefnInput, &mapInput);
5182 6 : if (ret != OGRERR_NONE)
5183 0 : goto done;
5184 6 : ret = create_field_map(poDefnMethod, &mapMethod);
5185 6 : if (ret != OGRERR_NONE)
5186 0 : goto done;
5187 6 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
5188 : mapMethod, false, papszOptions);
5189 6 : if (ret != OGRERR_NONE)
5190 0 : goto done;
5191 6 : poDefnResult = pLayerResult->GetLayerDefn();
5192 :
5193 : // add clipped features from the input layer
5194 18 : for (auto &&x : this)
5195 : {
5196 :
5197 12 : if (pfnProgress)
5198 : {
5199 2 : double p = progress_counter / progress_max;
5200 2 : if (p > progress_ticker)
5201 : {
5202 1 : if (!pfnProgress(p, "", pProgressArg))
5203 : {
5204 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5205 0 : ret = OGRERR_FAILURE;
5206 0 : goto done;
5207 : }
5208 : }
5209 2 : progress_counter += 1.0;
5210 : }
5211 :
5212 : // set up the filter on method layer
5213 12 : CPLErrorReset();
5214 : OGRGeometry *x_geom =
5215 12 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5216 12 : if (CPLGetLastErrorType() != CE_None)
5217 : {
5218 0 : if (!bSkipFailures)
5219 : {
5220 0 : ret = OGRERR_FAILURE;
5221 0 : goto done;
5222 : }
5223 : else
5224 : {
5225 0 : CPLErrorReset();
5226 0 : ret = OGRERR_NONE;
5227 : }
5228 : }
5229 12 : if (!x_geom)
5230 : {
5231 0 : continue;
5232 : }
5233 :
5234 : OGRGeometryUniquePtr x_geom_diff(
5235 12 : x_geom->clone()); // this will be the geometry of a result feature
5236 28 : for (auto &&y : pLayerMethod)
5237 : {
5238 16 : OGRGeometry *y_geom = y->GetGeometryRef();
5239 16 : if (!y_geom)
5240 0 : continue;
5241 16 : if (x_geom_diff)
5242 : {
5243 16 : CPLErrorReset();
5244 : OGRGeometryUniquePtr x_geom_diff_new(
5245 16 : x_geom_diff->Difference(y_geom));
5246 32 : if (CPLGetLastErrorType() != CE_None ||
5247 16 : x_geom_diff_new == nullptr)
5248 : {
5249 0 : if (!bSkipFailures)
5250 : {
5251 0 : ret = OGRERR_FAILURE;
5252 0 : goto done;
5253 : }
5254 : else
5255 : {
5256 0 : CPLErrorReset();
5257 0 : ret = OGRERR_NONE;
5258 : }
5259 : }
5260 : else
5261 : {
5262 16 : x_geom_diff.swap(x_geom_diff_new);
5263 : }
5264 : }
5265 : }
5266 :
5267 12 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
5268 : {
5269 : /* ok */
5270 : }
5271 : else
5272 : {
5273 7 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5274 7 : z->SetFieldsFrom(x.get(), mapInput);
5275 7 : if (bPromoteToMulti)
5276 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
5277 7 : z->SetGeometryDirectly(x_geom_diff.release());
5278 7 : ret = pLayerResult->CreateFeature(z.get());
5279 7 : if (ret != OGRERR_NONE)
5280 : {
5281 0 : if (!bSkipFailures)
5282 : {
5283 0 : goto done;
5284 : }
5285 : else
5286 : {
5287 0 : CPLErrorReset();
5288 0 : ret = OGRERR_NONE;
5289 : }
5290 : }
5291 : }
5292 : }
5293 :
5294 : // restore the original filter and add features from the update layer
5295 6 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5296 16 : for (auto &&y : pLayerMethod)
5297 : {
5298 :
5299 10 : if (pfnProgress)
5300 : {
5301 1 : double p = progress_counter / progress_max;
5302 1 : if (p > progress_ticker)
5303 : {
5304 1 : if (!pfnProgress(p, "", pProgressArg))
5305 : {
5306 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5307 0 : ret = OGRERR_FAILURE;
5308 0 : goto done;
5309 : }
5310 : }
5311 1 : progress_counter += 1.0;
5312 : }
5313 :
5314 10 : OGRGeometry *y_geom = y->StealGeometry();
5315 10 : if (!y_geom)
5316 0 : continue;
5317 10 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5318 10 : if (mapMethod)
5319 6 : z->SetFieldsFrom(y.get(), mapMethod);
5320 10 : z->SetGeometryDirectly(y_geom);
5321 10 : ret = pLayerResult->CreateFeature(z.get());
5322 10 : if (ret != OGRERR_NONE)
5323 : {
5324 0 : if (!bSkipFailures)
5325 : {
5326 0 : goto done;
5327 : }
5328 : else
5329 : {
5330 0 : CPLErrorReset();
5331 0 : ret = OGRERR_NONE;
5332 : }
5333 : }
5334 : }
5335 6 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5336 : {
5337 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5338 0 : ret = OGRERR_FAILURE;
5339 0 : goto done;
5340 : }
5341 6 : done:
5342 : // release resources
5343 6 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5344 6 : if (pGeometryMethodFilter)
5345 0 : delete pGeometryMethodFilter;
5346 6 : if (mapInput)
5347 4 : VSIFree(mapInput);
5348 6 : if (mapMethod)
5349 4 : VSIFree(mapMethod);
5350 6 : return ret;
5351 : }
5352 :
5353 : /************************************************************************/
5354 : /* OGR_L_Update() */
5355 : /************************************************************************/
5356 :
5357 : /**
5358 : * \brief Update this layer with features from the update layer.
5359 : *
5360 : * The result layer contains features whose geometries represent areas
5361 : * that are either in the input layer or in the method layer. The
5362 : * features in the result layer have areas of the features of the
5363 : * method layer or those ares of the features of the input layer that
5364 : * are not covered by the method layer. The features of the result
5365 : * layer get their attributes from the input layer. The schema of the
5366 : * result layer can be set by the user or, if it is empty, is
5367 : * initialized to contain all fields in the input layer.
5368 : *
5369 : * \note If the schema of the result is set by user and contains
5370 : * fields that have the same name as a field in the method layer, then
5371 : * the attribute in the result feature the originates from the method
5372 : * layer will get the value from the feature of the method layer.
5373 : *
5374 : * \note For best performance use the minimum amount of features in
5375 : * the method layer and copy it into a memory layer.
5376 : *
5377 : * \note This method relies on GEOS support. Do not use unless the
5378 : * GEOS support is compiled in.
5379 : *
5380 : * The recognized list of options is :
5381 : * <ul>
5382 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5383 : * feature could not be inserted or a GEOS call failed.
5384 : * </li>
5385 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5386 : * into MultiPolygons, LineStrings to MultiLineStrings or
5387 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5388 : * </li>
5389 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5390 : * will be created from the fields of the input layer.
5391 : * </li>
5392 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5393 : * will be created from the fields of the method layer.
5394 : * </li>
5395 : * </ul>
5396 : *
5397 : * This function is the same as the C++ method OGRLayer::Update().
5398 : *
5399 : * @param pLayerInput the input layer. Should not be NULL.
5400 : *
5401 : * @param pLayerMethod the method layer. Should not be NULL.
5402 : *
5403 : * @param pLayerResult the layer where the features resulting from the
5404 : * operation are inserted. Should not be NULL. See above the note
5405 : * about the schema.
5406 : *
5407 : * @param papszOptions NULL terminated list of options (may be NULL).
5408 : *
5409 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5410 : * reporting progress or NULL.
5411 : *
5412 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5413 : *
5414 : * @return an error code if there was an error or the execution was
5415 : * interrupted, OGRERR_NONE otherwise.
5416 : *
5417 : * @note The first geometry field is always used.
5418 : *
5419 : * @since OGR 1.10
5420 : */
5421 :
5422 5 : OGRErr OGR_L_Update(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5423 : OGRLayerH pLayerResult, char **papszOptions,
5424 : GDALProgressFunc pfnProgress, void *pProgressArg)
5425 :
5426 : {
5427 5 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE);
5428 5 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE);
5429 5 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE);
5430 :
5431 : return OGRLayer::FromHandle(pLayerInput)
5432 5 : ->Update(OGRLayer::FromHandle(pLayerMethod),
5433 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
5434 5 : pProgressArg);
5435 : }
5436 :
5437 : /************************************************************************/
5438 : /* Clip() */
5439 : /************************************************************************/
5440 :
5441 : /**
5442 : * \brief Clip off areas that are not covered by the method layer.
5443 : *
5444 : * The result layer contains features whose geometries represent areas
5445 : * that are in the input layer and in the method layer. The features
5446 : * in the result layer have the (possibly clipped) areas of features
5447 : * in the input layer and the attributes from the same features. The
5448 : * schema of the result layer can be set by the user or, if it is
5449 : * empty, is initialized to contain all fields in the input layer.
5450 : *
5451 : * \note For best performance use the minimum amount of features in
5452 : * the method layer and copy it into a memory layer.
5453 : *
5454 : * \note This method relies on GEOS support. Do not use unless the
5455 : * GEOS support is compiled in.
5456 : *
5457 : * The recognized list of options is :
5458 : * <ul>
5459 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5460 : * feature could not be inserted or a GEOS call failed.
5461 : * </li>
5462 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5463 : * into MultiPolygons, LineStrings to MultiLineStrings or
5464 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5465 : * </li>
5466 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5467 : * will be created from the fields of the input layer.
5468 : * </li>
5469 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5470 : * will be created from the fields of the method layer.
5471 : * </li>
5472 : * </ul>
5473 : *
5474 : * This method is the same as the C function OGR_L_Clip().
5475 : *
5476 : * @param pLayerMethod the method layer. Should not be NULL.
5477 : *
5478 : * @param pLayerResult the layer where the features resulting from the
5479 : * operation are inserted. Should not be NULL. See above the note
5480 : * about the schema.
5481 : *
5482 : * @param papszOptions NULL terminated list of options (may be NULL).
5483 : *
5484 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5485 : * reporting progress or NULL.
5486 : *
5487 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5488 : *
5489 : * @return an error code if there was an error or the execution was
5490 : * interrupted, OGRERR_NONE otherwise.
5491 : *
5492 : * @note The first geometry field is always used.
5493 : *
5494 : * @since OGR 1.10
5495 : */
5496 :
5497 4 : OGRErr OGRLayer::Clip(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5498 : char **papszOptions, GDALProgressFunc pfnProgress,
5499 : void *pProgressArg)
5500 : {
5501 4 : OGRErr ret = OGRERR_NONE;
5502 4 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
5503 4 : OGRFeatureDefn *poDefnResult = nullptr;
5504 4 : OGRGeometry *pGeometryMethodFilter = nullptr;
5505 4 : int *mapInput = nullptr;
5506 4 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
5507 4 : double progress_counter = 0;
5508 4 : double progress_ticker = 0;
5509 : const bool bSkipFailures =
5510 4 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5511 4 : const bool bPromoteToMulti = CPLTestBool(
5512 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5513 :
5514 : // check for GEOS
5515 4 : if (!OGRGeometryFactory::haveGEOS())
5516 : {
5517 0 : CPLError(CE_Failure, CPLE_AppDefined,
5518 : "OGRLayer::Clip() requires GEOS support");
5519 0 : return OGRERR_UNSUPPORTED_OPERATION;
5520 : }
5521 :
5522 4 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5523 4 : if (ret != OGRERR_NONE)
5524 0 : goto done;
5525 4 : ret = create_field_map(poDefnInput, &mapInput);
5526 4 : if (ret != OGRERR_NONE)
5527 0 : goto done;
5528 4 : ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
5529 : nullptr, false, papszOptions);
5530 4 : if (ret != OGRERR_NONE)
5531 0 : goto done;
5532 :
5533 4 : poDefnResult = pLayerResult->GetLayerDefn();
5534 12 : for (auto &&x : this)
5535 : {
5536 :
5537 8 : if (pfnProgress)
5538 : {
5539 2 : double p = progress_counter / progress_max;
5540 2 : if (p > progress_ticker)
5541 : {
5542 1 : if (!pfnProgress(p, "", pProgressArg))
5543 : {
5544 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5545 0 : ret = OGRERR_FAILURE;
5546 0 : goto done;
5547 : }
5548 : }
5549 2 : progress_counter += 1.0;
5550 : }
5551 :
5552 : // set up the filter on method layer
5553 8 : CPLErrorReset();
5554 : OGRGeometry *x_geom =
5555 8 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5556 8 : if (CPLGetLastErrorType() != CE_None)
5557 : {
5558 0 : if (!bSkipFailures)
5559 : {
5560 0 : ret = OGRERR_FAILURE;
5561 0 : goto done;
5562 : }
5563 : else
5564 : {
5565 0 : CPLErrorReset();
5566 0 : ret = OGRERR_NONE;
5567 : }
5568 : }
5569 8 : if (!x_geom)
5570 : {
5571 0 : continue;
5572 : }
5573 :
5574 : OGRGeometryUniquePtr
5575 0 : geom; // this will be the geometry of the result feature
5576 : // incrementally add area from y to geom
5577 16 : for (auto &&y : pLayerMethod)
5578 : {
5579 8 : OGRGeometry *y_geom = y->GetGeometryRef();
5580 8 : if (!y_geom)
5581 0 : continue;
5582 8 : if (!geom)
5583 : {
5584 8 : geom.reset(y_geom->clone());
5585 : }
5586 : else
5587 : {
5588 0 : CPLErrorReset();
5589 0 : OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
5590 0 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
5591 : {
5592 0 : if (!bSkipFailures)
5593 : {
5594 0 : ret = OGRERR_FAILURE;
5595 0 : goto done;
5596 : }
5597 : else
5598 : {
5599 0 : CPLErrorReset();
5600 0 : ret = OGRERR_NONE;
5601 : }
5602 : }
5603 : else
5604 : {
5605 0 : geom.swap(geom_new);
5606 : }
5607 : }
5608 : }
5609 :
5610 : // possibly add a new feature with area x intersection sum of y
5611 8 : if (geom)
5612 : {
5613 8 : CPLErrorReset();
5614 : OGRGeometryUniquePtr poIntersection(
5615 8 : x_geom->Intersection(geom.get()));
5616 8 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
5617 : {
5618 0 : if (!bSkipFailures)
5619 : {
5620 0 : ret = OGRERR_FAILURE;
5621 0 : goto done;
5622 : }
5623 : else
5624 : {
5625 0 : CPLErrorReset();
5626 0 : ret = OGRERR_NONE;
5627 : }
5628 : }
5629 8 : else if (!poIntersection->IsEmpty())
5630 : {
5631 8 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5632 8 : z->SetFieldsFrom(x.get(), mapInput);
5633 8 : if (bPromoteToMulti)
5634 2 : poIntersection.reset(
5635 : promote_to_multi(poIntersection.release()));
5636 8 : z->SetGeometryDirectly(poIntersection.release());
5637 8 : ret = pLayerResult->CreateFeature(z.get());
5638 8 : if (ret != OGRERR_NONE)
5639 : {
5640 0 : if (!bSkipFailures)
5641 : {
5642 0 : goto done;
5643 : }
5644 : else
5645 : {
5646 0 : CPLErrorReset();
5647 0 : ret = OGRERR_NONE;
5648 : }
5649 : }
5650 : }
5651 : }
5652 : }
5653 4 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5654 : {
5655 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5656 0 : ret = OGRERR_FAILURE;
5657 0 : goto done;
5658 : }
5659 4 : done:
5660 : // release resources
5661 4 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5662 4 : if (pGeometryMethodFilter)
5663 0 : delete pGeometryMethodFilter;
5664 4 : if (mapInput)
5665 4 : VSIFree(mapInput);
5666 4 : return ret;
5667 : }
5668 :
5669 : /************************************************************************/
5670 : /* OGR_L_Clip() */
5671 : /************************************************************************/
5672 :
5673 : /**
5674 : * \brief Clip off areas that are not covered by the method layer.
5675 : *
5676 : * The result layer contains features whose geometries represent areas
5677 : * that are in the input layer and in the method layer. The features
5678 : * in the result layer have the (possibly clipped) areas of features
5679 : * in the input layer and the attributes from the same features. The
5680 : * schema of the result layer can be set by the user or, if it is
5681 : * empty, is initialized to contain all fields in the input layer.
5682 : *
5683 : * \note For best performance use the minimum amount of features in
5684 : * the method layer and copy it into a memory layer.
5685 : *
5686 : * \note This method relies on GEOS support. Do not use unless the
5687 : * GEOS support is compiled in.
5688 : *
5689 : * The recognized list of options is :
5690 : * <ul>
5691 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5692 : * feature could not be inserted or a GEOS call failed.
5693 : * </li>
5694 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5695 : * into MultiPolygons, LineStrings to MultiLineStrings or
5696 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5697 : * </li>
5698 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5699 : * will be created from the fields of the input layer.
5700 : * </li>
5701 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5702 : * will be created from the fields of the method layer.
5703 : * </li>
5704 : * </ul>
5705 : *
5706 : * This function is the same as the C++ method OGRLayer::Clip().
5707 : *
5708 : * @param pLayerInput the input layer. Should not be NULL.
5709 : *
5710 : * @param pLayerMethod the method layer. Should not be NULL.
5711 : *
5712 : * @param pLayerResult the layer where the features resulting from the
5713 : * operation are inserted. Should not be NULL. See above the note
5714 : * about the schema.
5715 : *
5716 : * @param papszOptions NULL terminated list of options (may be NULL).
5717 : *
5718 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5719 : * reporting progress or NULL.
5720 : *
5721 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5722 : *
5723 : * @return an error code if there was an error or the execution was
5724 : * interrupted, OGRERR_NONE otherwise.
5725 : *
5726 : * @note The first geometry field is always used.
5727 : *
5728 : * @since OGR 1.10
5729 : */
5730 :
5731 3 : OGRErr OGR_L_Clip(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5732 : OGRLayerH pLayerResult, char **papszOptions,
5733 : GDALProgressFunc pfnProgress, void *pProgressArg)
5734 :
5735 : {
5736 3 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5737 3 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5738 3 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5739 :
5740 : return OGRLayer::FromHandle(pLayerInput)
5741 3 : ->Clip(OGRLayer::FromHandle(pLayerMethod),
5742 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
5743 3 : pProgressArg);
5744 : }
5745 :
5746 : /************************************************************************/
5747 : /* Erase() */
5748 : /************************************************************************/
5749 :
5750 : /**
5751 : * \brief Remove areas that are covered by the method layer.
5752 : *
5753 : * The result layer contains features whose geometries represent areas
5754 : * that are in the input layer but not in the method layer. The
5755 : * features in the result layer have attributes from the input
5756 : * layer. The schema of the result layer can be set by the user or, if
5757 : * it is empty, is initialized to contain all fields in the input
5758 : * layer.
5759 : *
5760 : * \note For best performance use the minimum amount of features in
5761 : * the method layer and copy it into a memory layer.
5762 : *
5763 : * \note This method relies on GEOS support. Do not use unless the
5764 : * GEOS support is compiled in.
5765 : *
5766 : * The recognized list of options is :
5767 : * <ul>
5768 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5769 : * feature could not be inserted or a GEOS call failed.
5770 : * </li>
5771 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5772 : * into MultiPolygons, LineStrings to MultiLineStrings or
5773 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5774 : * </li>
5775 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5776 : * will be created from the fields of the input layer.
5777 : * </li>
5778 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5779 : * will be created from the fields of the method layer.
5780 : * </li>
5781 : * </ul>
5782 : *
5783 : * This method is the same as the C function OGR_L_Erase().
5784 : *
5785 : * @param pLayerMethod the method layer. Should not be NULL.
5786 : *
5787 : * @param pLayerResult the layer where the features resulting from the
5788 : * operation are inserted. Should not be NULL. See above the note
5789 : * about the schema.
5790 : *
5791 : * @param papszOptions NULL terminated list of options (may be NULL).
5792 : *
5793 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5794 : * reporting progress or NULL.
5795 : *
5796 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5797 : *
5798 : * @return an error code if there was an error or the execution was
5799 : * interrupted, OGRERR_NONE otherwise.
5800 : *
5801 : * @note The first geometry field is always used.
5802 : *
5803 : * @since OGR 1.10
5804 : */
5805 :
5806 7 : OGRErr OGRLayer::Erase(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5807 : char **papszOptions, GDALProgressFunc pfnProgress,
5808 : void *pProgressArg)
5809 : {
5810 7 : OGRErr ret = OGRERR_NONE;
5811 7 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
5812 7 : OGRFeatureDefn *poDefnResult = nullptr;
5813 7 : OGRGeometry *pGeometryMethodFilter = nullptr;
5814 7 : int *mapInput = nullptr;
5815 7 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
5816 7 : double progress_counter = 0;
5817 7 : double progress_ticker = 0;
5818 : const bool bSkipFailures =
5819 7 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5820 7 : const bool bPromoteToMulti = CPLTestBool(
5821 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5822 :
5823 : // check for GEOS
5824 7 : if (!OGRGeometryFactory::haveGEOS())
5825 : {
5826 0 : CPLError(CE_Failure, CPLE_AppDefined,
5827 : "OGRLayer::Erase() requires GEOS support");
5828 0 : return OGRERR_UNSUPPORTED_OPERATION;
5829 : }
5830 :
5831 : // get resources
5832 7 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5833 7 : if (ret != OGRERR_NONE)
5834 0 : goto done;
5835 7 : ret = create_field_map(poDefnInput, &mapInput);
5836 7 : if (ret != OGRERR_NONE)
5837 0 : goto done;
5838 7 : ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
5839 : nullptr, false, papszOptions);
5840 7 : if (ret != OGRERR_NONE)
5841 0 : goto done;
5842 7 : poDefnResult = pLayerResult->GetLayerDefn();
5843 :
5844 21 : for (auto &&x : this)
5845 : {
5846 :
5847 14 : if (pfnProgress)
5848 : {
5849 2 : double p = progress_counter / progress_max;
5850 2 : if (p > progress_ticker)
5851 : {
5852 1 : if (!pfnProgress(p, "", pProgressArg))
5853 : {
5854 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5855 0 : ret = OGRERR_FAILURE;
5856 0 : goto done;
5857 : }
5858 : }
5859 2 : progress_counter += 1.0;
5860 : }
5861 :
5862 : // set up the filter on the method layer
5863 14 : CPLErrorReset();
5864 : OGRGeometry *x_geom =
5865 14 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5866 14 : if (CPLGetLastErrorType() != CE_None)
5867 : {
5868 0 : if (!bSkipFailures)
5869 : {
5870 0 : ret = OGRERR_FAILURE;
5871 0 : goto done;
5872 : }
5873 : else
5874 : {
5875 0 : CPLErrorReset();
5876 0 : ret = OGRERR_NONE;
5877 : }
5878 : }
5879 14 : if (!x_geom)
5880 : {
5881 0 : continue;
5882 : }
5883 :
5884 : OGRGeometryUniquePtr geom(
5885 : x_geom
5886 14 : ->clone()); // this will be the geometry of the result feature
5887 : // incrementally erase y from geom
5888 22 : for (auto &&y : pLayerMethod)
5889 : {
5890 11 : OGRGeometry *y_geom = y->GetGeometryRef();
5891 11 : if (!y_geom)
5892 0 : continue;
5893 11 : CPLErrorReset();
5894 11 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
5895 11 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
5896 : {
5897 0 : if (!bSkipFailures)
5898 : {
5899 0 : ret = OGRERR_FAILURE;
5900 0 : goto done;
5901 : }
5902 : else
5903 : {
5904 0 : CPLErrorReset();
5905 0 : ret = OGRERR_NONE;
5906 : }
5907 : }
5908 : else
5909 : {
5910 11 : geom.swap(geom_new);
5911 11 : if (geom->IsEmpty())
5912 : {
5913 3 : break;
5914 : }
5915 : }
5916 : }
5917 :
5918 : // add a new feature if there is remaining area
5919 14 : if (!geom->IsEmpty())
5920 : {
5921 11 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5922 11 : z->SetFieldsFrom(x.get(), mapInput);
5923 11 : if (bPromoteToMulti)
5924 4 : geom.reset(promote_to_multi(geom.release()));
5925 11 : z->SetGeometryDirectly(geom.release());
5926 11 : ret = pLayerResult->CreateFeature(z.get());
5927 11 : if (ret != OGRERR_NONE)
5928 : {
5929 0 : if (!bSkipFailures)
5930 : {
5931 0 : goto done;
5932 : }
5933 : else
5934 : {
5935 0 : CPLErrorReset();
5936 0 : ret = OGRERR_NONE;
5937 : }
5938 : }
5939 : }
5940 : }
5941 7 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5942 : {
5943 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5944 0 : ret = OGRERR_FAILURE;
5945 0 : goto done;
5946 : }
5947 7 : done:
5948 : // release resources
5949 7 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5950 7 : if (pGeometryMethodFilter)
5951 0 : delete pGeometryMethodFilter;
5952 7 : if (mapInput)
5953 6 : VSIFree(mapInput);
5954 7 : return ret;
5955 : }
5956 :
5957 : /************************************************************************/
5958 : /* OGR_L_Erase() */
5959 : /************************************************************************/
5960 :
5961 : /**
5962 : * \brief Remove areas that are covered by the method layer.
5963 : *
5964 : * The result layer contains features whose geometries represent areas
5965 : * that are in the input layer but not in the method layer. The
5966 : * features in the result layer have attributes from the input
5967 : * layer. The schema of the result layer can be set by the user or, if
5968 : * it is empty, is initialized to contain all fields in the input
5969 : * layer.
5970 : *
5971 : * \note For best performance use the minimum amount of features in
5972 : * the method layer and copy it into a memory layer.
5973 : *
5974 : * \note This method relies on GEOS support. Do not use unless the
5975 : * GEOS support is compiled in.
5976 : *
5977 : * The recognized list of options is :
5978 : * <ul>
5979 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5980 : * feature could not be inserted or a GEOS call failed.
5981 : * </li>
5982 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5983 : * into MultiPolygons, LineStrings to MultiLineStrings or
5984 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5985 : * </li>
5986 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5987 : * will be created from the fields of the input layer.
5988 : * </li>
5989 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5990 : * will be created from the fields of the method layer.
5991 : * </li>
5992 : * </ul>
5993 : *
5994 : * This function is the same as the C++ method OGRLayer::Erase().
5995 : *
5996 : * @param pLayerInput the input layer. Should not be NULL.
5997 : *
5998 : * @param pLayerMethod the method layer. Should not be NULL.
5999 : *
6000 : * @param pLayerResult the layer where the features resulting from the
6001 : * operation are inserted. Should not be NULL. See above the note
6002 : * about the schema.
6003 : *
6004 : * @param papszOptions NULL terminated list of options (may be NULL).
6005 : *
6006 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
6007 : * reporting progress or NULL.
6008 : *
6009 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
6010 : *
6011 : * @return an error code if there was an error or the execution was
6012 : * interrupted, OGRERR_NONE otherwise.
6013 : *
6014 : * @note The first geometry field is always used.
6015 : *
6016 : * @since OGR 1.10
6017 : */
6018 :
6019 6 : OGRErr OGR_L_Erase(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
6020 : OGRLayerH pLayerResult, char **papszOptions,
6021 : GDALProgressFunc pfnProgress, void *pProgressArg)
6022 :
6023 : {
6024 6 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
6025 6 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
6026 6 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
6027 :
6028 : return OGRLayer::FromHandle(pLayerInput)
6029 6 : ->Erase(OGRLayer::FromHandle(pLayerMethod),
6030 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
6031 6 : pProgressArg);
6032 : }
6033 :
6034 : /************************************************************************/
6035 : /* OGRLayer::FeatureIterator::Private */
6036 : /************************************************************************/
6037 :
6038 : struct OGRLayer::FeatureIterator::Private
6039 : {
6040 : CPL_DISALLOW_COPY_ASSIGN(Private)
6041 36964 : Private() = default;
6042 :
6043 : OGRFeatureUniquePtr m_poFeature{};
6044 : OGRLayer *m_poLayer = nullptr;
6045 : bool m_bError = false;
6046 : bool m_bEOF = true;
6047 : };
6048 :
6049 : /************************************************************************/
6050 : /* OGRLayer::FeatureIterator::FeatureIterator() */
6051 : /************************************************************************/
6052 :
6053 36964 : OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
6054 36964 : : m_poPrivate(new OGRLayer::FeatureIterator::Private())
6055 : {
6056 36964 : m_poPrivate->m_poLayer = poLayer;
6057 36964 : if (bStart)
6058 : {
6059 18482 : if (m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator)
6060 : {
6061 1 : CPLError(CE_Failure, CPLE_NotSupported,
6062 : "Only one feature iterator can be "
6063 : "active at a time");
6064 1 : m_poPrivate->m_bError = true;
6065 : }
6066 : else
6067 : {
6068 18481 : m_poPrivate->m_poLayer->ResetReading();
6069 36962 : m_poPrivate->m_poFeature.reset(
6070 18481 : m_poPrivate->m_poLayer->GetNextFeature());
6071 18481 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
6072 18481 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
6073 : }
6074 : }
6075 36964 : }
6076 :
6077 : /************************************************************************/
6078 : /* ~OGRLayer::FeatureIterator::FeatureIterator() */
6079 : /************************************************************************/
6080 :
6081 36964 : OGRLayer::FeatureIterator::~FeatureIterator()
6082 : {
6083 36964 : if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
6084 36963 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
6085 36964 : }
6086 :
6087 : /************************************************************************/
6088 : /* operator*() */
6089 : /************************************************************************/
6090 :
6091 156042 : OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
6092 : {
6093 156042 : return m_poPrivate->m_poFeature;
6094 : }
6095 :
6096 : /************************************************************************/
6097 : /* operator++() */
6098 : /************************************************************************/
6099 :
6100 155339 : OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
6101 : {
6102 155339 : m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
6103 155339 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
6104 155339 : return *this;
6105 : }
6106 :
6107 : /************************************************************************/
6108 : /* operator!=() */
6109 : /************************************************************************/
6110 :
6111 173821 : bool OGRLayer::FeatureIterator::operator!=(
6112 : const OGRLayer::FeatureIterator &it) const
6113 : {
6114 173821 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
6115 : }
6116 :
6117 : /************************************************************************/
6118 : /* begin() */
6119 : /************************************************************************/
6120 :
6121 18482 : OGRLayer::FeatureIterator OGRLayer::begin()
6122 : {
6123 18482 : return {this, true};
6124 : }
6125 :
6126 : /************************************************************************/
6127 : /* end() */
6128 : /************************************************************************/
6129 :
6130 18482 : OGRLayer::FeatureIterator OGRLayer::end()
6131 : {
6132 18482 : return {this, false};
6133 : }
6134 :
6135 : /************************************************************************/
6136 : /* OGRLayer::GetGeometryTypes() */
6137 : /************************************************************************/
6138 :
6139 : /** \brief Get actual geometry types found in features.
6140 : *
6141 : * This method iterates over features to retrieve their geometry types. This
6142 : * is mostly useful for layers that report a wkbUnknown geometry type with
6143 : * GetGeomType() or GetGeomFieldDefn(iGeomField)->GetType().
6144 : *
6145 : * By default this method returns an array of nEntryCount entries with each
6146 : * geometry type (in OGRGeometryTypeCounter::eGeomType) and the corresponding
6147 : * number of features (in OGRGeometryTypeCounter::nCount).
6148 : * Features without geometries are reported as eGeomType == wkbNone.
6149 : *
6150 : * The nFlagsGGT parameter can be a combination (with binary or operator) of the
6151 : * following hints:
6152 : * <ul>
6153 : * <li>OGR_GGT_COUNT_NOT_NEEDED: to indicate that only the set of geometry types
6154 : * matter, not the number of features per geometry type. Consequently the value
6155 : * of OGRGeometryTypeCounter::nCount should be ignored.</li>
6156 : * <li>OGR_GGT_STOP_IF_MIXED: to indicate that the implementation may stop
6157 : * iterating over features as soon as 2 different geometry types (not counting
6158 : * null geometries) are found. The value of OGRGeometryTypeCounter::nCount
6159 : * should be ignored (zero might be systematically reported by some
6160 : * implementations).</li> <li>OGR_GGT_GEOMCOLLECTIONZ_TINZ: to indicate that if
6161 : * a geometry is of type wkbGeometryCollection25D and its first sub-geometry is
6162 : * of type wkbTINZ, wkbTINZ should be reported as geometry type. This is mostly
6163 : * useful for the ESRI Shapefile and (Open)FileGDB drivers regarding MultiPatch
6164 : * geometries.</li>
6165 : * </ul>
6166 : *
6167 : * If the layer has no features, a non-NULL returned array with nEntryCount == 0
6168 : * will be returned.
6169 : *
6170 : * Spatial and/or attribute filters will be taken into account.
6171 : *
6172 : * This method will error out on a layer without geometry fields
6173 : * (GetGeomType() == wkbNone).
6174 : *
6175 : * A cancellation callback may be provided. The progress percentage it is called
6176 : * with is not relevant. The callback should return TRUE if processing should go
6177 : * on, or FALSE if it should be interrupted.
6178 : *
6179 : * @param iGeomField Geometry field index.
6180 : * @param nFlagsGGT Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
6181 : * OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
6182 : * @param[out] nEntryCountOut Number of entries in the returned array.
6183 : * @param pfnProgress Cancellation callback. May be NULL.
6184 : * @param pProgressData User data for the cancellation callback. May be NULL.
6185 : * @return an array of nEntryCount that must be freed with CPLFree(),
6186 : * or NULL in case of error
6187 : * @since GDAL 3.6
6188 : */
6189 : OGRGeometryTypeCounter *
6190 12 : OGRLayer::GetGeometryTypes(int iGeomField, int nFlagsGGT, int &nEntryCountOut,
6191 : GDALProgressFunc pfnProgress, void *pProgressData)
6192 : {
6193 12 : OGRFeatureDefn *poDefn = GetLayerDefn();
6194 12 : const int nGeomFieldCount = poDefn->GetGeomFieldCount();
6195 12 : if (iGeomField < 0 || iGeomField >= nGeomFieldCount)
6196 : {
6197 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for iGeomField");
6198 1 : nEntryCountOut = 0;
6199 1 : return nullptr;
6200 : }
6201 :
6202 : // Ignore all fields but the geometry one of interest
6203 22 : CPLStringList aosIgnoredFieldsRestore;
6204 22 : CPLStringList aosIgnoredFields;
6205 11 : const int nFieldCount = poDefn->GetFieldCount();
6206 33 : for (int iField = 0; iField < nFieldCount; iField++)
6207 : {
6208 22 : const auto poFieldDefn = poDefn->GetFieldDefn(iField);
6209 22 : const char *pszName = poFieldDefn->GetNameRef();
6210 22 : if (poFieldDefn->IsIgnored())
6211 10 : aosIgnoredFieldsRestore.AddString(pszName);
6212 22 : if (iField != iGeomField)
6213 11 : aosIgnoredFields.AddString(pszName);
6214 : }
6215 33 : for (int iField = 0; iField < nGeomFieldCount; iField++)
6216 : {
6217 22 : const auto poFieldDefn = poDefn->GetGeomFieldDefn(iField);
6218 22 : const char *pszName = poFieldDefn->GetNameRef();
6219 22 : if (poFieldDefn->IsIgnored())
6220 10 : aosIgnoredFieldsRestore.AddString(pszName);
6221 22 : if (iField != iGeomField)
6222 11 : aosIgnoredFields.AddString(pszName);
6223 : }
6224 11 : if (poDefn->IsStyleIgnored())
6225 0 : aosIgnoredFieldsRestore.AddString("OGR_STYLE");
6226 11 : aosIgnoredFields.AddString("OGR_STYLE");
6227 11 : SetIgnoredFields(aosIgnoredFields.List());
6228 :
6229 : // Iterate over features
6230 22 : std::map<OGRwkbGeometryType, int64_t> oMapCount;
6231 22 : std::set<OGRwkbGeometryType> oSetNotNull;
6232 11 : const bool bGeomCollectionZTInZ =
6233 11 : (nFlagsGGT & OGR_GGT_GEOMCOLLECTIONZ_TINZ) != 0;
6234 11 : const bool bStopIfMixed = (nFlagsGGT & OGR_GGT_STOP_IF_MIXED) != 0;
6235 11 : if (pfnProgress == GDALDummyProgress)
6236 0 : pfnProgress = nullptr;
6237 11 : bool bInterrupted = false;
6238 47 : for (auto &&poFeature : *this)
6239 : {
6240 36 : const auto poGeom = poFeature->GetGeomFieldRef(iGeomField);
6241 36 : if (poGeom == nullptr)
6242 : {
6243 18 : ++oMapCount[wkbNone];
6244 : }
6245 : else
6246 : {
6247 18 : auto eGeomType = poGeom->getGeometryType();
6248 18 : if (bGeomCollectionZTInZ && eGeomType == wkbGeometryCollection25D)
6249 : {
6250 1 : const auto poGC = poGeom->toGeometryCollection();
6251 1 : if (poGC->getNumGeometries() > 0)
6252 : {
6253 : auto eSubGeomType =
6254 1 : poGC->getGeometryRef(0)->getGeometryType();
6255 1 : if (eSubGeomType == wkbTINZ)
6256 1 : eGeomType = wkbTINZ;
6257 : }
6258 : }
6259 18 : ++oMapCount[eGeomType];
6260 18 : if (bStopIfMixed)
6261 : {
6262 4 : oSetNotNull.insert(eGeomType);
6263 4 : if (oSetNotNull.size() == 2)
6264 2 : break;
6265 : }
6266 : }
6267 34 : if (pfnProgress && !pfnProgress(0.0, "", pProgressData))
6268 : {
6269 1 : bInterrupted = true;
6270 1 : break;
6271 : }
6272 : }
6273 :
6274 : // Restore ignore fields state
6275 11 : SetIgnoredFields(aosIgnoredFieldsRestore.List());
6276 :
6277 11 : if (bInterrupted)
6278 : {
6279 1 : nEntryCountOut = 0;
6280 1 : return nullptr;
6281 : }
6282 :
6283 : // Format result
6284 10 : nEntryCountOut = static_cast<int>(oMapCount.size());
6285 : OGRGeometryTypeCounter *pasRet = static_cast<OGRGeometryTypeCounter *>(
6286 10 : CPLCalloc(1 + nEntryCountOut, sizeof(OGRGeometryTypeCounter)));
6287 10 : int i = 0;
6288 37 : for (const auto &oIter : oMapCount)
6289 : {
6290 27 : pasRet[i].eGeomType = oIter.first;
6291 27 : pasRet[i].nCount = oIter.second;
6292 27 : ++i;
6293 : }
6294 10 : return pasRet;
6295 : }
6296 :
6297 : /************************************************************************/
6298 : /* OGR_L_GetGeometryTypes() */
6299 : /************************************************************************/
6300 :
6301 : /** \brief Get actual geometry types found in features.
6302 : *
6303 : * See OGRLayer::GetGeometryTypes() for details.
6304 : *
6305 : * @param hLayer Layer.
6306 : * @param iGeomField Geometry field index.
6307 : * @param nFlags Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
6308 : * OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
6309 : * @param[out] pnEntryCount Pointer to the number of entries in the returned
6310 : * array. Must not be NULL.
6311 : * @param pfnProgress Cancellation callback. May be NULL.
6312 : * @param pProgressData User data for the cancellation callback. May be NULL.
6313 : * @return an array of *pnEntryCount that must be freed with CPLFree(),
6314 : * or NULL in case of error
6315 : * @since GDAL 3.6
6316 : */
6317 54 : OGRGeometryTypeCounter *OGR_L_GetGeometryTypes(OGRLayerH hLayer, int iGeomField,
6318 : int nFlags, int *pnEntryCount,
6319 : GDALProgressFunc pfnProgress,
6320 : void *pProgressData)
6321 : {
6322 54 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryTypes", nullptr);
6323 54 : VALIDATE_POINTER1(pnEntryCount, "OGR_L_GetGeometryTypes", nullptr);
6324 :
6325 108 : return OGRLayer::FromHandle(hLayer)->GetGeometryTypes(
6326 54 : iGeomField, nFlags, *pnEntryCount, pfnProgress, pProgressData);
6327 : }
6328 :
6329 : /************************************************************************/
6330 : /* OGRLayer::GetSupportedSRSList() */
6331 : /************************************************************************/
6332 :
6333 : /** \brief Get the list of SRS supported.
6334 : *
6335 : * The base implementation of this method will return an empty list. Some
6336 : * drivers (OAPIF, WFS) may return a non-empty list.
6337 : *
6338 : * One of the SRS returned may be passed to SetActiveSRS() to change the
6339 : * active SRS.
6340 : *
6341 : * @param iGeomField Geometry field index.
6342 : * @return list of supported SRS.
6343 : * @since GDAL 3.7
6344 : */
6345 : const OGRLayer::GetSupportedSRSListRetType &
6346 176 : OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
6347 : {
6348 176 : static OGRLayer::GetSupportedSRSListRetType empty;
6349 176 : return empty;
6350 : }
6351 :
6352 : /************************************************************************/
6353 : /* OGR_L_GetSupportedSRSList() */
6354 : /************************************************************************/
6355 :
6356 : /** \brief Get the list of SRS supported.
6357 : *
6358 : * The base implementation of this method will return an empty list. Some
6359 : * drivers (OAPIF, WFS) may return a non-empty list.
6360 : *
6361 : * One of the SRS returned may be passed to SetActiveSRS() to change the
6362 : * active SRS.
6363 : *
6364 : * @param hLayer Layer.
6365 : * @param iGeomField Geometry field index.
6366 : * @param[out] pnCount Number of values in returned array. Must not be null.
6367 : * @return list of supported SRS, to be freed with OSRFreeSRSArray(), or
6368 : * nullptr
6369 : * @since GDAL 3.7
6370 : */
6371 4 : OGRSpatialReferenceH *OGR_L_GetSupportedSRSList(OGRLayerH hLayer,
6372 : int iGeomField, int *pnCount)
6373 : {
6374 4 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSupportedSRSList", nullptr);
6375 4 : VALIDATE_POINTER1(pnCount, "OGR_L_GetSupportedSRSList", nullptr);
6376 :
6377 : const auto &srsList =
6378 4 : OGRLayer::FromHandle(hLayer)->GetSupportedSRSList(iGeomField);
6379 4 : *pnCount = static_cast<int>(srsList.size());
6380 4 : if (srsList.empty())
6381 : {
6382 2 : return nullptr;
6383 : }
6384 : OGRSpatialReferenceH *pahRet = static_cast<OGRSpatialReferenceH *>(
6385 2 : CPLMalloc((1 + srsList.size()) * sizeof(OGRSpatialReferenceH)));
6386 2 : size_t i = 0;
6387 7 : for (const auto &poSRS : srsList)
6388 : {
6389 5 : poSRS->Reference();
6390 5 : pahRet[i] = OGRSpatialReference::ToHandle(poSRS.get());
6391 5 : ++i;
6392 : }
6393 2 : pahRet[i] = nullptr;
6394 2 : return pahRet;
6395 : }
6396 :
6397 : /************************************************************************/
6398 : /* OGRLayer::SetActiveSRS() */
6399 : /************************************************************************/
6400 :
6401 : /** \brief Change the active SRS.
6402 : *
6403 : * The passed SRS must be in the list returned by GetSupportedSRSList()
6404 : * (the actual pointer may be different, but should be tested as identical
6405 : * with OGRSpatialReference::IsSame()).
6406 : *
6407 : * Changing the active SRS affects:
6408 : * <ul>
6409 : * <li>the SRS in which geometries of returned features are expressed,</li>
6410 : * <li>the SRS in which geometries of passed features (CreateFeature(),
6411 : * SetFeature()) are expressed,</li>
6412 : * <li>the SRS returned by GetSpatialRef() and
6413 : * GetGeomFieldDefn()->GetSpatialRef(),</li>
6414 : * <li>the SRS used to interpret SetSpatialFilter() values.</li>
6415 : * </ul>
6416 : * This also resets feature reading and the spatial filter.
6417 : * Note however that this does not modify the storage SRS of the features of
6418 : * geometries. Said otherwise, this setting is volatile and has no persistent
6419 : * effects after dataset reopening.
6420 : *
6421 : * @param iGeomField Geometry field index.
6422 : * @param poSRS SRS to use
6423 : * @return OGRERR_NONE in case of success, or OGRERR_FAILURE if
6424 : * the passed SRS is not in GetSupportedSRSList()
6425 : * @since GDAL 3.7
6426 : */
6427 1 : OGRErr OGRLayer::SetActiveSRS(CPL_UNUSED int iGeomField,
6428 : CPL_UNUSED const OGRSpatialReference *poSRS)
6429 : {
6430 1 : return OGRERR_FAILURE;
6431 : }
6432 :
6433 : /************************************************************************/
6434 : /* OGR_L_SetActiveSRS() */
6435 : /************************************************************************/
6436 :
6437 : /** \brief Change the active SRS.
6438 : *
6439 : * The passed SRS must be in the list returned by GetSupportedSRSList()
6440 : * (the actual pointer may be different, but should be tested as identical
6441 : * with OGRSpatialReference::IsSame()).
6442 : *
6443 : * Changing the active SRS affects:
6444 : * <ul>
6445 : * <li>the SRS in which geometries of returned features are expressed,</li>
6446 : * <li>the SRS in which geometries of passed features (CreateFeature(),
6447 : * SetFeature()) are expressed,</li>
6448 : * <li>the SRS returned by GetSpatialRef() and
6449 : * GetGeomFieldDefn()->GetSpatialRef(),</li>
6450 : * <li>the SRS used to interpret SetSpatialFilter() values.</li>
6451 : * </ul>
6452 : * This also resets feature reading and the spatial filter.
6453 : * Note however that this does not modify the storage SRS of the features of
6454 : * geometries. Said otherwise, this setting is volatile and has no persistent
6455 : * effects after dataset reopening.
6456 : *
6457 : * @param hLayer Layer.
6458 : * @param iGeomField Geometry field index.
6459 : * @param hSRS SRS to use
6460 : * @return OGRERR_NONE in case of success, OGRERR_FAILURE if
6461 : * the passed SRS is not in GetSupportedSRSList().
6462 : * @since GDAL 3.7
6463 : */
6464 9 : OGRErr OGR_L_SetActiveSRS(OGRLayerH hLayer, int iGeomField,
6465 : OGRSpatialReferenceH hSRS)
6466 : {
6467 9 : VALIDATE_POINTER1(hLayer, "OGR_L_SetActiveSRS", OGRERR_FAILURE);
6468 18 : return OGRLayer::FromHandle(hLayer)->SetActiveSRS(
6469 9 : iGeomField, OGRSpatialReference::FromHandle(hSRS));
6470 : }
6471 :
6472 : /************************************************************************/
6473 : /* GetDataset() */
6474 : /************************************************************************/
6475 :
6476 : /** Return the dataset associated with this layer.
6477 : *
6478 : * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
6479 : * have CreateLayer() capability. It may not be implemented in read-only
6480 : * drivers or out-of-tree drivers.
6481 : *
6482 : * It is currently only used by the GetRecordBatchSchema()
6483 : * method to retrieve the field domain associated with a field, to fill the
6484 : * dictionary field of a struct ArrowSchema.
6485 : * It is also used by CreateFieldFromArrowSchema() to determine which field
6486 : * types and subtypes are supported by the layer, by inspecting the driver
6487 : * metadata, and potentially use fallback types when needed.
6488 : *
6489 : * This method is the same as the C function OGR_L_GetDataset().
6490 : *
6491 : * @return dataset, or nullptr when unknown.
6492 : * @since GDAL 3.6
6493 : */
6494 1 : GDALDataset *OGRLayer::GetDataset()
6495 : {
6496 1 : return nullptr;
6497 : }
6498 :
6499 : /************************************************************************/
6500 : /* OGR_L_GetDataset() */
6501 : /************************************************************************/
6502 :
6503 : /** Return the dataset associated with this layer.
6504 : *
6505 : * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
6506 : * have CreateLayer() capability. It may not be implemented in read-only
6507 : * drivers or out-of-tree drivers.
6508 : *
6509 : * It is currently only used by the GetRecordBatchSchema()
6510 : * method to retrieve the field domain associated with a field, to fill the
6511 : * dictionary field of a struct ArrowSchema.
6512 : * It is also used by CreateFieldFromArrowSchema() to determine which field
6513 : * types and subtypes are supported by the layer, by inspecting the driver
6514 : * metadata, and potentially use fallback types when needed.
6515 : *
6516 : * This function is the same as the C++ method OGRLayer::GetDataset().
6517 : *
6518 : * @return dataset, or nullptr when unknown.
6519 : * @since GDAL 3.9
6520 : */
6521 264 : GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
6522 : {
6523 264 : VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
6524 264 : return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
6525 : }
|