Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: The generic portions of the OGRSFLayer class.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 1999, Les Technologies SoftMap Inc.
9 : * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "ogrsf_frmts.h"
15 : #include "ogr_api.h"
16 : #include "ogr_p.h"
17 : #include "ogr_attrind.h"
18 : #include "ogr_swq.h"
19 : #include "ograpispy.h"
20 : #include "ogr_wkb.h"
21 : #include "ogrlayer_private.h"
22 :
23 : #include "cpl_time.h"
24 : #include <cassert>
25 : #include <cmath>
26 : #include <limits>
27 : #include <memory>
28 : #include <set>
29 :
30 : /************************************************************************/
31 : /* OGRLayer() */
32 : /************************************************************************/
33 :
34 74799 : OGRLayer::OGRLayer()
35 74799 : : m_poPrivate(new Private()), m_bFilterIsEnvelope(FALSE),
36 : m_poFilterGeom(nullptr),
37 : m_pPreparedFilterGeom(nullptr), m_sFilterEnvelope{},
38 : m_iGeomFieldFilter(0), m_poStyleTable(nullptr), m_poAttrQuery(nullptr),
39 : m_pszAttrQueryString(nullptr), m_poAttrIndex(nullptr), m_nRefCount(0),
40 149598 : m_nFeaturesRead(0)
41 : {
42 74799 : }
43 :
44 : /************************************************************************/
45 : /* ~OGRLayer() */
46 : /************************************************************************/
47 :
48 74591 : OGRLayer::~OGRLayer()
49 :
50 : {
51 74591 : if (m_poStyleTable)
52 : {
53 11 : delete m_poStyleTable;
54 11 : m_poStyleTable = nullptr;
55 : }
56 :
57 74591 : if (m_poAttrIndex != nullptr)
58 : {
59 169 : delete m_poAttrIndex;
60 169 : m_poAttrIndex = nullptr;
61 : }
62 :
63 74591 : if (m_poAttrQuery != nullptr)
64 : {
65 641 : delete m_poAttrQuery;
66 641 : m_poAttrQuery = nullptr;
67 : }
68 :
69 74591 : CPLFree(m_pszAttrQueryString);
70 :
71 74591 : if (m_poFilterGeom)
72 : {
73 875 : delete m_poFilterGeom;
74 875 : m_poFilterGeom = nullptr;
75 : }
76 :
77 74591 : if (m_pPreparedFilterGeom != nullptr)
78 : {
79 875 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
80 875 : m_pPreparedFilterGeom = nullptr;
81 : }
82 :
83 74591 : if (m_poSharedArrowArrayStreamPrivateData != nullptr)
84 : {
85 685 : m_poSharedArrowArrayStreamPrivateData->m_poLayer = nullptr;
86 : }
87 74591 : }
88 :
89 : /************************************************************************/
90 : /* Reference() */
91 : /************************************************************************/
92 :
93 0 : int OGRLayer::Reference()
94 :
95 : {
96 0 : return ++m_nRefCount;
97 : }
98 :
99 : /************************************************************************/
100 : /* OGR_L_Reference() */
101 : /************************************************************************/
102 :
103 0 : int OGR_L_Reference(OGRLayerH hLayer)
104 :
105 : {
106 0 : VALIDATE_POINTER1(hLayer, "OGR_L_Reference", 0);
107 :
108 0 : return OGRLayer::FromHandle(hLayer)->Reference();
109 : }
110 :
111 : /************************************************************************/
112 : /* Dereference() */
113 : /************************************************************************/
114 :
115 0 : int OGRLayer::Dereference()
116 :
117 : {
118 0 : return --m_nRefCount;
119 : }
120 :
121 : /************************************************************************/
122 : /* OGR_L_Dereference() */
123 : /************************************************************************/
124 :
125 0 : int OGR_L_Dereference(OGRLayerH hLayer)
126 :
127 : {
128 0 : VALIDATE_POINTER1(hLayer, "OGR_L_Dereference", 0);
129 :
130 0 : return OGRLayer::FromHandle(hLayer)->Dereference();
131 : }
132 :
133 : /************************************************************************/
134 : /* GetRefCount() */
135 : /************************************************************************/
136 :
137 0 : int OGRLayer::GetRefCount() const
138 :
139 : {
140 0 : return m_nRefCount;
141 : }
142 :
143 : /************************************************************************/
144 : /* OGR_L_GetRefCount() */
145 : /************************************************************************/
146 :
147 0 : int OGR_L_GetRefCount(OGRLayerH hLayer)
148 :
149 : {
150 0 : VALIDATE_POINTER1(hLayer, "OGR_L_GetRefCount", 0);
151 :
152 0 : return OGRLayer::FromHandle(hLayer)->GetRefCount();
153 : }
154 :
155 : /************************************************************************/
156 : /* GetFeatureCount() */
157 : /************************************************************************/
158 :
159 13859 : GIntBig OGRLayer::GetFeatureCount(int bForce)
160 :
161 : {
162 13859 : if (!bForce)
163 1 : return -1;
164 :
165 13858 : GIntBig nFeatureCount = 0;
166 55411 : for (auto &&poFeature : *this)
167 : {
168 41553 : CPL_IGNORE_RET_VAL(poFeature.get());
169 41553 : nFeatureCount++;
170 : }
171 13858 : ResetReading();
172 :
173 13858 : return nFeatureCount;
174 : }
175 :
176 : /************************************************************************/
177 : /* OGR_L_GetFeatureCount() */
178 : /************************************************************************/
179 :
180 36972 : GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
181 :
182 : {
183 36972 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
184 :
185 : #ifdef OGRAPISPY_ENABLED
186 36972 : if (bOGRAPISpyEnabled)
187 2 : OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
188 : #endif
189 :
190 36972 : return OGRLayer::FromHandle(hLayer)->GetFeatureCount(bForce);
191 : }
192 :
193 : /************************************************************************/
194 : /* GetExtent() */
195 : /************************************************************************/
196 :
197 : /**
198 : \brief Fetch the extent of this layer.
199 :
200 : Returns the extent (MBR) of the data in the layer. If bForce is FALSE,
201 : and it would be expensive to establish the extent then OGRERR_FAILURE
202 : will be returned indicating that the extent isn't know. If bForce is
203 : TRUE then some implementations will actually scan the entire layer once
204 : to compute the MBR of all the features in the layer.
205 :
206 : Depending on the drivers, the returned extent may or may not take the
207 : spatial filter into account. So it is safer to call GetExtent() without
208 : setting a spatial filter.
209 :
210 : Layers without any geometry may return OGRERR_FAILURE just indicating that
211 : no meaningful extents could be collected.
212 :
213 : Note that some implementations of this method may alter the read cursor
214 : of the layer.
215 :
216 : This method is the same as the C function OGR_L_GetExtent().
217 :
218 : @param psExtent the structure in which the extent value will be returned.
219 : @param bForce Flag indicating whether the extent should be computed even
220 : if it is expensive.
221 :
222 : @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
223 : */
224 :
225 15397 : OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, bool bForce)
226 : {
227 15397 : return GetExtent(0, psExtent, bForce);
228 : }
229 :
230 : /**
231 : \brief Fetch the extent of this layer, on the specified geometry field.
232 :
233 : Returns the extent (MBR) of the data in the layer. If bForce is FALSE,
234 : and it would be expensive to establish the extent then OGRERR_FAILURE
235 : will be returned indicating that the extent isn't know. If bForce is
236 : TRUE then some implementations will actually scan the entire layer once
237 : to compute the MBR of all the features in the layer.
238 :
239 : Depending on the drivers, the returned extent may or may not take the
240 : spatial filter into account. So it is safer to call GetExtent() without
241 : setting a spatial filter.
242 :
243 : Layers without any geometry may return OGRERR_FAILURE just indicating that
244 : no meaningful extents could be collected.
245 :
246 : Note that some implementations of this method may alter the read cursor
247 : of the layer.
248 :
249 : This method is the same as the C function OGR_L_GetExtentEx().
250 :
251 : @param iGeomField the index of the geometry field on which to compute the extent.
252 : @param psExtent the structure in which the extent value will be returned.
253 : @param bForce Flag indicating whether the extent should be computed even
254 : if it is expensive.
255 :
256 : @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
257 :
258 : */
259 :
260 17486 : OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
261 : {
262 17486 : psExtent->MinX = 0.0;
263 17486 : psExtent->MaxX = 0.0;
264 17486 : psExtent->MinY = 0.0;
265 17486 : psExtent->MaxY = 0.0;
266 :
267 : /* -------------------------------------------------------------------- */
268 : /* If this layer has a none geometry type, then we can */
269 : /* reasonably assume there are not extents available. */
270 : /* -------------------------------------------------------------------- */
271 34204 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
272 16718 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
273 : {
274 768 : if (iGeomField != 0)
275 : {
276 610 : CPLError(CE_Failure, CPLE_AppDefined,
277 : "Invalid geometry field index : %d", iGeomField);
278 : }
279 768 : return OGRERR_FAILURE;
280 : }
281 :
282 16718 : return IGetExtent(iGeomField, psExtent, bForce);
283 : }
284 :
285 : /************************************************************************/
286 : /* IGetExtent() */
287 : /************************************************************************/
288 :
289 : /**
290 : \brief Fetch the extent of this layer, on the specified geometry field.
291 :
292 : Virtual method implemented by drivers since 3.11. In previous versions,
293 : GetExtent() itself was the virtual method.
294 :
295 : Driver implementations, when wanting to call the base method, must take
296 : care of calling OGRLayer::IGetExtent() (and note the public method without
297 : the leading I).
298 :
299 : @param iGeomField 0-based index of the geometry field to consider.
300 : @param psExtent the computed extent of the layer.
301 : @param bForce if TRUE, the extent will be computed even if all the
302 : layer features have to be fetched.
303 : @return OGRERR_NONE on success or an error code in case of failure.
304 : @since GDAL 3.11
305 : */
306 :
307 461 : OGRErr OGRLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent, bool bForce)
308 :
309 : {
310 : /* -------------------------------------------------------------------- */
311 : /* If not forced, we should avoid having to scan all the */
312 : /* features and just return a failure. */
313 : /* -------------------------------------------------------------------- */
314 461 : if (!bForce)
315 1 : return OGRERR_FAILURE;
316 :
317 : /* -------------------------------------------------------------------- */
318 : /* OK, we hate to do this, but go ahead and read through all */
319 : /* the features to collect geometries and build extents. */
320 : /* -------------------------------------------------------------------- */
321 460 : OGREnvelope oEnv;
322 460 : bool bExtentSet = false;
323 :
324 9885 : for (auto &&poFeature : *this)
325 : {
326 9425 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
327 9425 : if (poGeom == nullptr || poGeom->IsEmpty())
328 : {
329 : /* Do nothing */
330 : }
331 9122 : else if (!bExtentSet)
332 : {
333 410 : poGeom->getEnvelope(psExtent);
334 820 : if (!(std::isnan(psExtent->MinX) || std::isnan(psExtent->MinY) ||
335 410 : std::isnan(psExtent->MaxX) || std::isnan(psExtent->MaxY)))
336 : {
337 410 : bExtentSet = true;
338 : }
339 : }
340 : else
341 : {
342 8712 : poGeom->getEnvelope(&oEnv);
343 8712 : if (oEnv.MinX < psExtent->MinX)
344 325 : psExtent->MinX = oEnv.MinX;
345 8712 : if (oEnv.MinY < psExtent->MinY)
346 376 : psExtent->MinY = oEnv.MinY;
347 8712 : if (oEnv.MaxX > psExtent->MaxX)
348 944 : psExtent->MaxX = oEnv.MaxX;
349 8712 : if (oEnv.MaxY > psExtent->MaxY)
350 927 : psExtent->MaxY = oEnv.MaxY;
351 : }
352 : }
353 460 : ResetReading();
354 :
355 460 : return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
356 : }
357 :
358 : /************************************************************************/
359 : /* OGR_L_GetExtent() */
360 : /************************************************************************/
361 :
362 : /**
363 : \brief Fetch the extent of this layer.
364 :
365 : Returns the extent (MBR) of the data in the layer. If bForce is FALSE,
366 : and it would be expensive to establish the extent then OGRERR_FAILURE
367 : will be returned indicating that the extent isn't know. If bForce is
368 : TRUE then some implementations will actually scan the entire layer once
369 : to compute the MBR of all the features in the layer.
370 :
371 : Depending on the drivers, the returned extent may or may not take the
372 : spatial filter into account. So it is safer to call OGR_L_GetExtent() without
373 : setting a spatial filter.
374 :
375 : Layers without any geometry may return OGRERR_FAILURE just indicating that
376 : no meaningful extents could be collected.
377 :
378 : Note that some implementations of this method may alter the read cursor
379 : of the layer.
380 :
381 : This function is the same as the C++ method OGRLayer::GetExtent().
382 :
383 : @param hLayer handle to the layer from which to get extent.
384 : @param psExtent the structure in which the extent value will be returned.
385 : @param bForce Flag indicating whether the extent should be computed even
386 : if it is expensive.
387 :
388 : @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
389 :
390 : */
391 :
392 29 : OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
393 :
394 : {
395 29 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
396 :
397 : #ifdef OGRAPISPY_ENABLED
398 29 : if (bOGRAPISpyEnabled)
399 0 : OGRAPISpy_L_GetExtent(hLayer, bForce);
400 : #endif
401 :
402 29 : return OGRLayer::FromHandle(hLayer)->GetExtent(0, psExtent,
403 29 : bForce != FALSE);
404 : }
405 :
406 : /************************************************************************/
407 : /* OGR_L_GetExtentEx() */
408 : /************************************************************************/
409 :
410 : /**
411 : \brief Fetch the extent of this layer, on the specified geometry field.
412 :
413 : Returns the extent (MBR) of the data in the layer. If bForce is FALSE,
414 : and it would be expensive to establish the extent then OGRERR_FAILURE
415 : will be returned indicating that the extent isn't know. If bForce is
416 : TRUE then some implementations will actually scan the entire layer once
417 : to compute the MBR of all the features in the layer.
418 :
419 : Depending on the drivers, the returned extent may or may not take the
420 : spatial filter into account. So it is safer to call OGR_L_GetExtent() without
421 : setting a spatial filter.
422 :
423 : Layers without any geometry may return OGRERR_FAILURE just indicating that
424 : no meaningful extents could be collected.
425 :
426 : Note that some implementations of this method may alter the read cursor
427 : of the layer.
428 :
429 : This function is the same as the C++ method OGRLayer::GetExtent().
430 :
431 : @param hLayer handle to the layer from which to get extent.
432 : @param iGeomField the index of the geometry field on which to compute the extent.
433 : @param psExtent the structure in which the extent value will be returned.
434 : @param bForce Flag indicating whether the extent should be computed even
435 : if it is expensive.
436 :
437 : @return OGRERR_NONE on success, OGRERR_FAILURE if extent not known.
438 :
439 : */
440 378 : OGRErr OGR_L_GetExtentEx(OGRLayerH hLayer, int iGeomField,
441 : OGREnvelope *psExtent, int bForce)
442 :
443 : {
444 378 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE);
445 :
446 : #ifdef OGRAPISPY_ENABLED
447 378 : if (bOGRAPISpyEnabled)
448 4 : OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
449 : #endif
450 :
451 378 : return OGRLayer::FromHandle(hLayer)->GetExtent(iGeomField, psExtent,
452 378 : bForce != FALSE);
453 : }
454 :
455 : /************************************************************************/
456 : /* GetExtent3D() */
457 : /************************************************************************/
458 :
459 : /**
460 : \brief Fetch the 3D extent of this layer, on the specified geometry field.
461 :
462 : Returns the 3D extent (MBR) of the data in the layer. If bForce is FALSE,
463 : and it would be expensive to establish the extent then OGRERR_FAILURE
464 : will be returned indicating that the extent isn't know. If bForce is
465 : TRUE then some implementations will actually scan the entire layer once
466 : to compute the MBR of all the features in the layer.
467 :
468 : (Contrarty to GetExtent() 2D), the returned extent will always take into
469 : account the attribute and spatial filters that may be installed.
470 :
471 : Layers without any geometry may return OGRERR_FAILURE just indicating that
472 : no meaningful extents could be collected.
473 :
474 : For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
475 : fields will be respectively set to +Infinity and -Infinity.
476 :
477 : Note that some implementations of this method may alter the read cursor
478 : of the layer.
479 :
480 : This function is the same as the C function OGR_L_GetExtent3D().
481 :
482 : @param iGeomField 0-based index of the geometry field to consider.
483 : @param psExtent3D the computed 3D extent of the layer.
484 : @param bForce if TRUE, the extent will be computed even if all the
485 : layer features have to be fetched.
486 : @return OGRERR_NONE on success or an error code in case of failure.
487 : @since GDAL 3.9
488 : */
489 :
490 65 : OGRErr OGRLayer::GetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
491 : bool bForce)
492 :
493 : {
494 65 : psExtent3D->MinX = 0.0;
495 65 : psExtent3D->MaxX = 0.0;
496 65 : psExtent3D->MinY = 0.0;
497 65 : psExtent3D->MaxY = 0.0;
498 65 : psExtent3D->MinZ = std::numeric_limits<double>::infinity();
499 65 : psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
500 :
501 : /* -------------------------------------------------------------------- */
502 : /* If this layer has a none geometry type, then we can */
503 : /* reasonably assume there are not extents available. */
504 : /* -------------------------------------------------------------------- */
505 129 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
506 64 : GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone)
507 : {
508 1 : if (iGeomField != 0)
509 : {
510 0 : CPLError(CE_Failure, CPLE_AppDefined,
511 : "Invalid geometry field index : %d", iGeomField);
512 : }
513 1 : return OGRERR_FAILURE;
514 : }
515 :
516 64 : return IGetExtent3D(iGeomField, psExtent3D, bForce);
517 : }
518 :
519 : /************************************************************************/
520 : /* IGetExtent3D() */
521 : /************************************************************************/
522 :
523 : /**
524 : \brief Fetch the 3D extent of this layer, on the specified geometry field.
525 :
526 : See GetExtent3D() documentation.
527 :
528 : Virtual method implemented by drivers since 3.11. In previous versions,
529 : GetExtent3D() itself was the virtual method.
530 :
531 : Driver implementations, when wanting to call the base method, must take
532 : care of calling OGRLayer::IGetExtent3D() (and note the public method without
533 : the leading I).
534 :
535 : @param iGeomField 0-based index of the geometry field to consider.
536 : @param psExtent3D the computed 3D extent of the layer.
537 : @param bForce if TRUE, the extent will be computed even if all the
538 : layer features have to be fetched.
539 : @return OGRERR_NONE on success or an error code in case of failure.
540 : @since GDAL 3.11
541 : */
542 :
543 27 : OGRErr OGRLayer::IGetExtent3D(int iGeomField, OGREnvelope3D *psExtent3D,
544 : bool bForce)
545 :
546 : {
547 : /* -------------------------------------------------------------------- */
548 : /* If not forced, we should avoid having to scan all the */
549 : /* features and just return a failure. */
550 : /* -------------------------------------------------------------------- */
551 27 : if (!bForce)
552 0 : return OGRERR_FAILURE;
553 :
554 : /* -------------------------------------------------------------------- */
555 : /* OK, we hate to do this, but go ahead and read through all */
556 : /* the features to collect geometries and build extents. */
557 : /* -------------------------------------------------------------------- */
558 27 : OGREnvelope3D oEnv;
559 27 : bool bExtentSet = false;
560 :
561 133 : for (auto &&poFeature : *this)
562 : {
563 106 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
564 106 : if (poGeom == nullptr || poGeom->IsEmpty())
565 : {
566 : /* Do nothing */
567 : }
568 89 : else if (!bExtentSet)
569 : {
570 27 : poGeom->getEnvelope(psExtent3D);
571 : // This is required because getEnvelope initializes Z to 0 for 2D geometries
572 27 : if (!poGeom->Is3D())
573 : {
574 20 : psExtent3D->MinZ = std::numeric_limits<double>::infinity();
575 20 : psExtent3D->MaxZ = -std::numeric_limits<double>::infinity();
576 : }
577 27 : bExtentSet = true;
578 : }
579 : else
580 : {
581 62 : poGeom->getEnvelope(&oEnv);
582 : // This is required because getEnvelope initializes Z to 0 for 2D geometries
583 62 : if (!poGeom->Is3D())
584 : {
585 53 : oEnv.MinZ = std::numeric_limits<double>::infinity();
586 53 : oEnv.MaxZ = -std::numeric_limits<double>::infinity();
587 : }
588 : // Merge handles infinity correctly
589 62 : psExtent3D->Merge(oEnv);
590 : }
591 : }
592 27 : ResetReading();
593 :
594 27 : return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
595 : }
596 :
597 : /************************************************************************/
598 : /* OGR_L_GetExtent3D() */
599 : /************************************************************************/
600 :
601 : /**
602 : \brief Fetch the 3D extent of this layer, on the specified geometry field.
603 :
604 : Returns the 3D extent (MBR) of the data in the layer. If bForce is FALSE,
605 : and it would be expensive to establish the extent then OGRERR_FAILURE
606 : will be returned indicating that the extent isn't know. If bForce is
607 : TRUE then some implementations will actually scan the entire layer once
608 : to compute the MBR of all the features in the layer.
609 :
610 : (Contrarty to GetExtent() 2D), the returned extent will always take into
611 : account the attribute and spatial filters that may be installed.
612 :
613 : Layers without any geometry may return OGRERR_FAILURE just indicating that
614 : no meaningful extents could be collected.
615 :
616 : For layers that have no 3D geometries, the psExtent3D->MinZ and psExtent3D->MaxZ
617 : fields will be respectively set to +Infinity and -Infinity.
618 :
619 : Note that some implementations of this method may alter the read cursor
620 : of the layer.
621 :
622 : This function is the same as the C++ method OGRLayer::GetExtent3D().
623 :
624 : @param hLayer the layer to consider.
625 : @param iGeomField 0-based index of the geometry field to consider.
626 : @param psExtent3D the computed 3D extent of the layer.
627 : @param bForce if TRUE, the extent will be computed even if all the
628 : layer features have to be fetched.
629 : @return OGRERR_NONE on success or an error code in case of failure.
630 : @since GDAL 3.9
631 : */
632 :
633 60 : OGRErr OGR_L_GetExtent3D(OGRLayerH hLayer, int iGeomField,
634 : OGREnvelope3D *psExtent3D, int bForce)
635 :
636 : {
637 60 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent3D", OGRERR_INVALID_HANDLE);
638 :
639 : #ifdef OGRAPISPY_ENABLED
640 60 : if (bOGRAPISpyEnabled)
641 0 : OGRAPISpy_L_GetExtent3D(hLayer, iGeomField, bForce);
642 : #endif
643 :
644 60 : return OGRLayer::FromHandle(hLayer)->GetExtent3D(iGeomField, psExtent3D,
645 60 : bForce != FALSE);
646 : }
647 :
648 : /************************************************************************/
649 : /* SetAttributeFilter() */
650 : /************************************************************************/
651 :
652 15214 : OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
653 :
654 : {
655 15214 : CPLFree(m_pszAttrQueryString);
656 15214 : m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
657 :
658 : /* -------------------------------------------------------------------- */
659 : /* Are we just clearing any existing query? */
660 : /* -------------------------------------------------------------------- */
661 15214 : if (pszQuery == nullptr || strlen(pszQuery) == 0)
662 : {
663 10151 : if (m_poAttrQuery)
664 : {
665 2867 : delete m_poAttrQuery;
666 2867 : m_poAttrQuery = nullptr;
667 2867 : ResetReading();
668 : }
669 10151 : return OGRERR_NONE;
670 : }
671 :
672 : /* -------------------------------------------------------------------- */
673 : /* Or are we installing a new query? */
674 : /* -------------------------------------------------------------------- */
675 : OGRErr eErr;
676 :
677 5063 : if (!m_poAttrQuery)
678 3568 : m_poAttrQuery = new OGRFeatureQuery();
679 :
680 5063 : eErr = m_poAttrQuery->Compile(this, pszQuery);
681 5063 : if (eErr != OGRERR_NONE)
682 : {
683 3 : delete m_poAttrQuery;
684 3 : m_poAttrQuery = nullptr;
685 : }
686 :
687 5063 : ResetReading();
688 :
689 5063 : return eErr;
690 : }
691 :
692 : /************************************************************************/
693 : /* ContainGeomSpecialField() */
694 : /************************************************************************/
695 :
696 280 : static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
697 : {
698 280 : if (expr->eNodeType == SNT_COLUMN)
699 : {
700 59 : if (expr->table_index == 0 && expr->field_index != -1)
701 : {
702 59 : int nSpecialFieldIdx = expr->field_index - nLayerFieldCount;
703 59 : return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
704 118 : nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
705 59 : nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
706 : }
707 : }
708 221 : else if (expr->eNodeType == SNT_OPERATION)
709 : {
710 333 : for (int i = 0; i < expr->nSubExprCount; i++)
711 : {
712 218 : if (ContainGeomSpecialField(expr->papoSubExpr[i], nLayerFieldCount))
713 0 : return TRUE;
714 : }
715 : }
716 221 : return FALSE;
717 : }
718 :
719 : /************************************************************************/
720 : /* AttributeFilterEvaluationNeedsGeometry() */
721 : /************************************************************************/
722 :
723 : //! @cond Doxygen_Suppress
724 62 : int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
725 : {
726 62 : if (!m_poAttrQuery)
727 0 : return FALSE;
728 :
729 : swq_expr_node *expr =
730 62 : static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
731 62 : int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
732 :
733 62 : return ContainGeomSpecialField(expr, nLayerFieldCount);
734 : }
735 :
736 : //! @endcond
737 :
738 : /************************************************************************/
739 : /* OGR_L_SetAttributeFilter() */
740 : /************************************************************************/
741 :
742 1457 : OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszQuery)
743 :
744 : {
745 1457 : VALIDATE_POINTER1(hLayer, "OGR_L_SetAttributeFilter",
746 : OGRERR_INVALID_HANDLE);
747 :
748 : #ifdef OGRAPISPY_ENABLED
749 1457 : if (bOGRAPISpyEnabled)
750 4 : OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
751 : #endif
752 :
753 1457 : return OGRLayer::FromHandle(hLayer)->SetAttributeFilter(pszQuery);
754 : }
755 :
756 : /************************************************************************/
757 : /* GetFeature() */
758 : /************************************************************************/
759 :
760 1008 : OGRFeature *OGRLayer::GetFeature(GIntBig nFID)
761 :
762 : {
763 : /* Save old attribute and spatial filters */
764 : char *pszOldFilter =
765 1008 : m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
766 : OGRGeometry *poOldFilterGeom =
767 1008 : (m_poFilterGeom != nullptr) ? m_poFilterGeom->clone() : nullptr;
768 1008 : int iOldGeomFieldFilter = m_iGeomFieldFilter;
769 : /* Unset filters */
770 1008 : SetAttributeFilter(nullptr);
771 1008 : SetSpatialFilter(0, nullptr);
772 :
773 1008 : OGRFeatureUniquePtr poFeature;
774 14541 : for (auto &&poFeatureIter : *this)
775 : {
776 13533 : if (poFeatureIter->GetFID() == nFID)
777 : {
778 675 : poFeature.swap(poFeatureIter);
779 675 : break;
780 : }
781 : }
782 :
783 : /* Restore filters */
784 1008 : SetAttributeFilter(pszOldFilter);
785 1008 : CPLFree(pszOldFilter);
786 1008 : SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
787 1008 : delete poOldFilterGeom;
788 :
789 2016 : return poFeature.release();
790 : }
791 :
792 : /************************************************************************/
793 : /* OGR_L_GetFeature() */
794 : /************************************************************************/
795 :
796 2554 : OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
797 :
798 : {
799 2554 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
800 :
801 : #ifdef OGRAPISPY_ENABLED
802 2554 : if (bOGRAPISpyEnabled)
803 2 : OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
804 : #endif
805 :
806 2554 : return OGRFeature::ToHandle(
807 5108 : OGRLayer::FromHandle(hLayer)->GetFeature(nFeatureId));
808 : }
809 :
810 : /************************************************************************/
811 : /* SetNextByIndex() */
812 : /************************************************************************/
813 :
814 1087 : OGRErr OGRLayer::SetNextByIndex(GIntBig nIndex)
815 :
816 : {
817 1087 : if (nIndex < 0)
818 195 : nIndex = GINTBIG_MAX;
819 :
820 1087 : ResetReading();
821 :
822 132916 : while (nIndex-- > 0)
823 : {
824 132219 : auto poFeature = std::unique_ptr<OGRFeature>(GetNextFeature());
825 132219 : if (poFeature == nullptr)
826 390 : return OGRERR_NON_EXISTING_FEATURE;
827 : }
828 :
829 697 : return OGRERR_NONE;
830 : }
831 :
832 : /************************************************************************/
833 : /* OGR_L_SetNextByIndex() */
834 : /************************************************************************/
835 :
836 41 : OGRErr OGR_L_SetNextByIndex(OGRLayerH hLayer, GIntBig nIndex)
837 :
838 : {
839 41 : VALIDATE_POINTER1(hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE);
840 :
841 : #ifdef OGRAPISPY_ENABLED
842 41 : if (bOGRAPISpyEnabled)
843 2 : OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
844 : #endif
845 :
846 41 : return OGRLayer::FromHandle(hLayer)->SetNextByIndex(nIndex);
847 : }
848 :
849 : /************************************************************************/
850 : /* OGR_L_GetNextFeature() */
851 : /************************************************************************/
852 :
853 84196 : OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
854 :
855 : {
856 84196 : VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
857 :
858 : #ifdef OGRAPISPY_ENABLED
859 84196 : if (bOGRAPISpyEnabled)
860 8 : OGRAPISpy_L_GetNextFeature(hLayer);
861 : #endif
862 :
863 84196 : return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
864 : }
865 :
866 : /************************************************************************/
867 : /* ConvertGeomsIfNecessary() */
868 : /************************************************************************/
869 :
870 1012390 : void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
871 : {
872 1012390 : if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
873 : {
874 : // One time initialization
875 9706 : m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
876 9706 : m_poPrivate->m_bSupportsCurve =
877 9706 : CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
878 9706 : m_poPrivate->m_bSupportsM =
879 9706 : CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
880 9706 : if (CPLTestBool(
881 : CPLGetConfigOption("OGR_APPLY_GEOM_SET_PRECISION", "FALSE")))
882 : {
883 2 : const auto poFeatureDefn = GetLayerDefn();
884 2 : const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
885 2 : for (int i = 0; i < nGeomFieldCount; i++)
886 : {
887 2 : const double dfXYResolution = poFeatureDefn->GetGeomFieldDefn(i)
888 2 : ->GetCoordinatePrecision()
889 2 : .dfXYResolution;
890 4 : if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
891 2 : OGRGeometryFactory::haveGEOS())
892 : {
893 2 : m_poPrivate->m_bApplyGeomSetPrecision = true;
894 2 : break;
895 : }
896 : }
897 : }
898 : }
899 :
900 1933350 : if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
901 920956 : m_poPrivate->m_bApplyGeomSetPrecision)
902 : {
903 91437 : const auto poFeatureDefn = GetLayerDefn();
904 91437 : const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
905 180598 : for (int i = 0; i < nGeomFieldCount; i++)
906 : {
907 89161 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
908 89161 : if (poGeom)
909 : {
910 105494 : if (!m_poPrivate->m_bSupportsM &&
911 19314 : OGR_GT_HasM(poGeom->getGeometryType()))
912 : {
913 1 : poGeom->setMeasured(FALSE);
914 : }
915 :
916 172162 : if (!m_poPrivate->m_bSupportsCurve &&
917 85982 : OGR_GT_IsNonLinear(poGeom->getGeometryType()))
918 : {
919 : OGRwkbGeometryType eTargetType =
920 23 : OGR_GT_GetLinear(poGeom->getGeometryType());
921 23 : poGeom = OGRGeometryFactory::forceTo(
922 : poFeature->StealGeometry(i), eTargetType);
923 23 : poFeature->SetGeomFieldDirectly(i, poGeom);
924 23 : poGeom = poFeature->GetGeomFieldRef(i);
925 : }
926 :
927 86180 : if (poGeom && m_poPrivate->m_bApplyGeomSetPrecision)
928 : {
929 : const double dfXYResolution =
930 2 : poFeatureDefn->GetGeomFieldDefn(i)
931 2 : ->GetCoordinatePrecision()
932 2 : .dfXYResolution;
933 4 : if (dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN &&
934 2 : !poGeom->hasCurveGeometry())
935 : {
936 2 : auto poNewGeom = poGeom->SetPrecision(dfXYResolution,
937 : /* nFlags = */ 0);
938 2 : if (poNewGeom)
939 : {
940 2 : poFeature->SetGeomFieldDirectly(i, poNewGeom);
941 : // If there was potential further processing...
942 : // poGeom = poFeature->GetGeomFieldRef(i);
943 : }
944 : }
945 : }
946 : }
947 : }
948 : }
949 1012390 : }
950 :
951 : /************************************************************************/
952 : /* SetFeature() */
953 : /************************************************************************/
954 :
955 3589 : OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
956 :
957 : {
958 3589 : ConvertGeomsIfNecessary(poFeature);
959 3589 : return ISetFeature(poFeature);
960 : }
961 :
962 : /************************************************************************/
963 : /* ISetFeature() */
964 : /************************************************************************/
965 :
966 142 : OGRErr OGRLayer::ISetFeature(OGRFeature *)
967 :
968 : {
969 142 : return OGRERR_UNSUPPORTED_OPERATION;
970 : }
971 :
972 : /************************************************************************/
973 : /* OGR_L_SetFeature() */
974 : /************************************************************************/
975 :
976 2478 : OGRErr OGR_L_SetFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
977 :
978 : {
979 2478 : VALIDATE_POINTER1(hLayer, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
980 2478 : VALIDATE_POINTER1(hFeat, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE);
981 :
982 : #ifdef OGRAPISPY_ENABLED
983 2478 : if (bOGRAPISpyEnabled)
984 2 : OGRAPISpy_L_SetFeature(hLayer, hFeat);
985 : #endif
986 :
987 2478 : return OGRLayer::FromHandle(hLayer)->SetFeature(
988 2478 : OGRFeature::FromHandle(hFeat));
989 : }
990 :
991 : /************************************************************************/
992 : /* CreateFeature() */
993 : /************************************************************************/
994 :
995 1008690 : OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
996 :
997 : {
998 1008690 : ConvertGeomsIfNecessary(poFeature);
999 1008690 : return ICreateFeature(poFeature);
1000 : }
1001 :
1002 : /************************************************************************/
1003 : /* ICreateFeature() */
1004 : /************************************************************************/
1005 :
1006 0 : OGRErr OGRLayer::ICreateFeature(OGRFeature *)
1007 :
1008 : {
1009 0 : return OGRERR_UNSUPPORTED_OPERATION;
1010 : }
1011 :
1012 : /************************************************************************/
1013 : /* OGR_L_CreateFeature() */
1014 : /************************************************************************/
1015 :
1016 297674 : OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1017 :
1018 : {
1019 297674 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1020 297674 : VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
1021 :
1022 : #ifdef OGRAPISPY_ENABLED
1023 297674 : if (bOGRAPISpyEnabled)
1024 5 : OGRAPISpy_L_CreateFeature(hLayer, hFeat);
1025 : #endif
1026 :
1027 297674 : return OGRLayer::FromHandle(hLayer)->CreateFeature(
1028 297674 : OGRFeature::FromHandle(hFeat));
1029 : }
1030 :
1031 : /************************************************************************/
1032 : /* UpsertFeature() */
1033 : /************************************************************************/
1034 :
1035 33 : OGRErr OGRLayer::UpsertFeature(OGRFeature *poFeature)
1036 :
1037 : {
1038 33 : ConvertGeomsIfNecessary(poFeature);
1039 33 : return IUpsertFeature(poFeature);
1040 : }
1041 :
1042 : /************************************************************************/
1043 : /* IUpsertFeature() */
1044 : /************************************************************************/
1045 :
1046 0 : OGRErr OGRLayer::IUpsertFeature(OGRFeature *)
1047 : {
1048 0 : return OGRERR_UNSUPPORTED_OPERATION;
1049 : }
1050 :
1051 : /************************************************************************/
1052 : /* OGR_L_UpsertFeature() */
1053 : /************************************************************************/
1054 :
1055 31 : OGRErr OGR_L_UpsertFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
1056 :
1057 : {
1058 31 : VALIDATE_POINTER1(hLayer, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
1059 31 : VALIDATE_POINTER1(hFeat, "OGR_L_UpsertFeature", OGRERR_INVALID_HANDLE);
1060 :
1061 : #ifdef OGRAPISPY_ENABLED
1062 31 : if (bOGRAPISpyEnabled)
1063 0 : OGRAPISpy_L_UpsertFeature(hLayer, hFeat);
1064 : #endif
1065 :
1066 31 : return OGRLayer::FromHandle(hLayer)->UpsertFeature(
1067 31 : OGRFeature::FromHandle(hFeat));
1068 : }
1069 :
1070 : /************************************************************************/
1071 : /* UpdateFeature() */
1072 : /************************************************************************/
1073 :
1074 75 : OGRErr OGRLayer::UpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
1075 : const int *panUpdatedFieldsIdx,
1076 : int nUpdatedGeomFieldsCount,
1077 : const int *panUpdatedGeomFieldsIdx,
1078 : bool bUpdateStyleString)
1079 :
1080 : {
1081 75 : ConvertGeomsIfNecessary(poFeature);
1082 75 : const int nFieldCount = GetLayerDefn()->GetFieldCount();
1083 136 : for (int i = 0; i < nUpdatedFieldsCount; ++i)
1084 : {
1085 63 : if (panUpdatedFieldsIdx[i] < 0 || panUpdatedFieldsIdx[i] >= nFieldCount)
1086 : {
1087 2 : CPLError(CE_Failure, CPLE_AppDefined,
1088 : "Invalid panUpdatedFieldsIdx[%d] = %d", i,
1089 2 : panUpdatedFieldsIdx[i]);
1090 2 : return OGRERR_FAILURE;
1091 : }
1092 : }
1093 73 : const int nGeomFieldCount = GetLayerDefn()->GetGeomFieldCount();
1094 83 : for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
1095 : {
1096 12 : if (panUpdatedGeomFieldsIdx[i] < 0 ||
1097 11 : panUpdatedGeomFieldsIdx[i] >= nGeomFieldCount)
1098 : {
1099 2 : CPLError(CE_Failure, CPLE_AppDefined,
1100 : "Invalid panUpdatedGeomFieldsIdx[%d] = %d", i,
1101 2 : panUpdatedGeomFieldsIdx[i]);
1102 2 : return OGRERR_FAILURE;
1103 : }
1104 : }
1105 71 : return IUpdateFeature(poFeature, nUpdatedFieldsCount, panUpdatedFieldsIdx,
1106 : nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx,
1107 71 : bUpdateStyleString);
1108 : }
1109 :
1110 : /************************************************************************/
1111 : /* IUpdateFeature() */
1112 : /************************************************************************/
1113 :
1114 28 : OGRErr OGRLayer::IUpdateFeature(OGRFeature *poFeature, int nUpdatedFieldsCount,
1115 : const int *panUpdatedFieldsIdx,
1116 : int nUpdatedGeomFieldsCount,
1117 : const int *panUpdatedGeomFieldsIdx,
1118 : bool bUpdateStyleString)
1119 : {
1120 28 : if (!TestCapability(OLCRandomWrite))
1121 0 : return OGRERR_UNSUPPORTED_OPERATION;
1122 :
1123 : auto poFeatureExisting =
1124 56 : std::unique_ptr<OGRFeature>(GetFeature(poFeature->GetFID()));
1125 28 : if (!poFeatureExisting)
1126 1 : return OGRERR_NON_EXISTING_FEATURE;
1127 :
1128 52 : for (int i = 0; i < nUpdatedFieldsCount; ++i)
1129 : {
1130 25 : poFeatureExisting->SetField(
1131 25 : panUpdatedFieldsIdx[i],
1132 25 : poFeature->GetRawFieldRef(panUpdatedFieldsIdx[i]));
1133 : }
1134 29 : for (int i = 0; i < nUpdatedGeomFieldsCount; ++i)
1135 : {
1136 2 : poFeatureExisting->SetGeomFieldDirectly(
1137 2 : panUpdatedGeomFieldsIdx[i],
1138 2 : poFeature->StealGeometry(panUpdatedGeomFieldsIdx[i]));
1139 : }
1140 27 : if (bUpdateStyleString)
1141 : {
1142 0 : poFeatureExisting->SetStyleString(poFeature->GetStyleString());
1143 : }
1144 27 : return ISetFeature(poFeatureExisting.get());
1145 : }
1146 :
1147 : /************************************************************************/
1148 : /* OGR_L_UpdateFeature() */
1149 : /************************************************************************/
1150 :
1151 31 : OGRErr OGR_L_UpdateFeature(OGRLayerH hLayer, OGRFeatureH hFeat,
1152 : int nUpdatedFieldsCount,
1153 : const int *panUpdatedFieldsIdx,
1154 : int nUpdatedGeomFieldsCount,
1155 : const int *panUpdatedGeomFieldsIdx,
1156 : bool bUpdateStyleString)
1157 :
1158 : {
1159 31 : VALIDATE_POINTER1(hLayer, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
1160 31 : VALIDATE_POINTER1(hFeat, "OGR_L_UpdateFeature", OGRERR_INVALID_HANDLE);
1161 :
1162 31 : return OGRLayer::FromHandle(hLayer)->UpdateFeature(
1163 : OGRFeature::FromHandle(hFeat), nUpdatedFieldsCount, panUpdatedFieldsIdx,
1164 31 : nUpdatedGeomFieldsCount, panUpdatedGeomFieldsIdx, bUpdateStyleString);
1165 : }
1166 :
1167 : /************************************************************************/
1168 : /* CreateField() */
1169 : /************************************************************************/
1170 :
1171 80 : OGRErr OGRLayer::CreateField(const OGRFieldDefn *poField, int bApproxOK)
1172 :
1173 : {
1174 : (void)poField;
1175 : (void)bApproxOK;
1176 :
1177 80 : CPLError(CE_Failure, CPLE_NotSupported,
1178 : "CreateField() not supported by this layer.\n");
1179 :
1180 80 : return OGRERR_UNSUPPORTED_OPERATION;
1181 : }
1182 :
1183 : /************************************************************************/
1184 : /* OGR_L_CreateField() */
1185 : /************************************************************************/
1186 :
1187 77883 : OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
1188 :
1189 : {
1190 77883 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1191 77883 : VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
1192 :
1193 : #ifdef OGRAPISPY_ENABLED
1194 77883 : if (bOGRAPISpyEnabled)
1195 6 : OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
1196 : #endif
1197 :
1198 155766 : return OGRLayer::FromHandle(hLayer)->CreateField(
1199 77883 : OGRFieldDefn::FromHandle(hField), bApproxOK);
1200 : }
1201 :
1202 : /************************************************************************/
1203 : /* DeleteField() */
1204 : /************************************************************************/
1205 :
1206 0 : OGRErr OGRLayer::DeleteField(int iField)
1207 :
1208 : {
1209 : (void)iField;
1210 :
1211 0 : CPLError(CE_Failure, CPLE_NotSupported,
1212 : "DeleteField() not supported by this layer.\n");
1213 :
1214 0 : return OGRERR_UNSUPPORTED_OPERATION;
1215 : }
1216 :
1217 : /************************************************************************/
1218 : /* OGR_L_DeleteField() */
1219 : /************************************************************************/
1220 :
1221 374 : OGRErr OGR_L_DeleteField(OGRLayerH hLayer, int iField)
1222 :
1223 : {
1224 374 : VALIDATE_POINTER1(hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE);
1225 :
1226 : #ifdef OGRAPISPY_ENABLED
1227 374 : if (bOGRAPISpyEnabled)
1228 2 : OGRAPISpy_L_DeleteField(hLayer, iField);
1229 : #endif
1230 :
1231 374 : return OGRLayer::FromHandle(hLayer)->DeleteField(iField);
1232 : }
1233 :
1234 : /************************************************************************/
1235 : /* ReorderFields() */
1236 : /************************************************************************/
1237 :
1238 0 : OGRErr OGRLayer::ReorderFields(int *panMap)
1239 :
1240 : {
1241 : (void)panMap;
1242 :
1243 0 : CPLError(CE_Failure, CPLE_NotSupported,
1244 : "ReorderFields() not supported by this layer.\n");
1245 :
1246 0 : return OGRERR_UNSUPPORTED_OPERATION;
1247 : }
1248 :
1249 : /************************************************************************/
1250 : /* OGR_L_ReorderFields() */
1251 : /************************************************************************/
1252 :
1253 43 : OGRErr OGR_L_ReorderFields(OGRLayerH hLayer, int *panMap)
1254 :
1255 : {
1256 43 : VALIDATE_POINTER1(hLayer, "OGR_L_ReorderFields", OGRERR_INVALID_HANDLE);
1257 :
1258 : #ifdef OGRAPISPY_ENABLED
1259 43 : if (bOGRAPISpyEnabled)
1260 2 : OGRAPISpy_L_ReorderFields(hLayer, panMap);
1261 : #endif
1262 :
1263 43 : return OGRLayer::FromHandle(hLayer)->ReorderFields(panMap);
1264 : }
1265 :
1266 : /************************************************************************/
1267 : /* ReorderField() */
1268 : /************************************************************************/
1269 :
1270 34 : OGRErr OGRLayer::ReorderField(int iOldFieldPos, int iNewFieldPos)
1271 :
1272 : {
1273 : OGRErr eErr;
1274 :
1275 34 : int nFieldCount = GetLayerDefn()->GetFieldCount();
1276 :
1277 34 : if (iOldFieldPos < 0 || iOldFieldPos >= nFieldCount)
1278 : {
1279 0 : CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
1280 0 : return OGRERR_FAILURE;
1281 : }
1282 34 : if (iNewFieldPos < 0 || iNewFieldPos >= nFieldCount)
1283 : {
1284 0 : CPLError(CE_Failure, CPLE_NotSupported, "Invalid field index");
1285 0 : return OGRERR_FAILURE;
1286 : }
1287 34 : if (iNewFieldPos == iOldFieldPos)
1288 0 : return OGRERR_NONE;
1289 :
1290 34 : int *panMap = static_cast<int *>(CPLMalloc(sizeof(int) * nFieldCount));
1291 34 : if (iOldFieldPos < iNewFieldPos)
1292 : {
1293 : /* "0","1","2","3","4" (1,3) -> "0","2","3","1","4" */
1294 15 : int i = 0; // Used after for.
1295 19 : for (; i < iOldFieldPos; i++)
1296 4 : panMap[i] = i;
1297 40 : for (; i < iNewFieldPos; i++)
1298 25 : panMap[i] = i + 1;
1299 15 : panMap[iNewFieldPos] = iOldFieldPos;
1300 27 : for (i = iNewFieldPos + 1; i < nFieldCount; i++)
1301 12 : panMap[i] = i;
1302 : }
1303 : else
1304 : {
1305 : /* "0","1","2","3","4" (3,1) -> "0","3","1","2","4" */
1306 23 : for (int i = 0; i < iNewFieldPos; i++)
1307 4 : panMap[i] = i;
1308 19 : panMap[iNewFieldPos] = iOldFieldPos;
1309 19 : int i = iNewFieldPos + 1; // Used after for.
1310 67 : for (; i <= iOldFieldPos; i++)
1311 48 : panMap[i] = i - 1;
1312 31 : for (; i < nFieldCount; i++)
1313 12 : panMap[i] = i;
1314 : }
1315 :
1316 34 : eErr = ReorderFields(panMap);
1317 :
1318 34 : CPLFree(panMap);
1319 :
1320 34 : return eErr;
1321 : }
1322 :
1323 : /************************************************************************/
1324 : /* OGR_L_ReorderField() */
1325 : /************************************************************************/
1326 :
1327 34 : OGRErr OGR_L_ReorderField(OGRLayerH hLayer, int iOldFieldPos, int iNewFieldPos)
1328 :
1329 : {
1330 34 : VALIDATE_POINTER1(hLayer, "OGR_L_ReorderField", OGRERR_INVALID_HANDLE);
1331 :
1332 : #ifdef OGRAPISPY_ENABLED
1333 34 : if (bOGRAPISpyEnabled)
1334 2 : OGRAPISpy_L_ReorderField(hLayer, iOldFieldPos, iNewFieldPos);
1335 : #endif
1336 :
1337 34 : return OGRLayer::FromHandle(hLayer)->ReorderField(iOldFieldPos,
1338 34 : iNewFieldPos);
1339 : }
1340 :
1341 : /************************************************************************/
1342 : /* AlterFieldDefn() */
1343 : /************************************************************************/
1344 :
1345 0 : OGRErr OGRLayer::AlterFieldDefn(int /* iField*/,
1346 : OGRFieldDefn * /*poNewFieldDefn*/,
1347 : int /* nFlags */)
1348 :
1349 : {
1350 0 : CPLError(CE_Failure, CPLE_NotSupported,
1351 : "AlterFieldDefn() not supported by this layer.\n");
1352 :
1353 0 : return OGRERR_UNSUPPORTED_OPERATION;
1354 : }
1355 :
1356 : /************************************************************************/
1357 : /* OGR_L_AlterFieldDefn() */
1358 : /************************************************************************/
1359 :
1360 126 : OGRErr OGR_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
1361 : OGRFieldDefnH hNewFieldDefn, int nFlags)
1362 :
1363 : {
1364 126 : VALIDATE_POINTER1(hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE);
1365 126 : VALIDATE_POINTER1(hNewFieldDefn, "OGR_L_AlterFieldDefn",
1366 : OGRERR_INVALID_HANDLE);
1367 :
1368 : #ifdef OGRAPISPY_ENABLED
1369 126 : if (bOGRAPISpyEnabled)
1370 2 : OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
1371 : #endif
1372 :
1373 252 : return OGRLayer::FromHandle(hLayer)->AlterFieldDefn(
1374 126 : iField, OGRFieldDefn::FromHandle(hNewFieldDefn), nFlags);
1375 : }
1376 :
1377 : /************************************************************************/
1378 : /* AlterGeomFieldDefn() */
1379 : /************************************************************************/
1380 :
1381 : OGRErr
1382 0 : OGRLayer::AlterGeomFieldDefn(int /* iGeomField*/,
1383 : const OGRGeomFieldDefn * /*poNewGeomFieldDefn*/,
1384 : int /* nFlags */)
1385 :
1386 : {
1387 0 : CPLError(CE_Failure, CPLE_NotSupported,
1388 : "AlterGeomFieldDefn() not supported by this layer.\n");
1389 :
1390 0 : return OGRERR_UNSUPPORTED_OPERATION;
1391 : }
1392 :
1393 : /************************************************************************/
1394 : /* OGR_L_AlterGeomFieldDefn() */
1395 : /************************************************************************/
1396 :
1397 33 : OGRErr OGR_L_AlterGeomFieldDefn(OGRLayerH hLayer, int iGeomField,
1398 : OGRGeomFieldDefnH hNewGeomFieldDefn, int nFlags)
1399 :
1400 : {
1401 33 : VALIDATE_POINTER1(hLayer, "OGR_L_AlterGeomFieldDefn",
1402 : OGRERR_INVALID_HANDLE);
1403 33 : VALIDATE_POINTER1(hNewGeomFieldDefn, "OGR_L_AlterGeomFieldDefn",
1404 : OGRERR_INVALID_HANDLE);
1405 :
1406 66 : return OGRLayer::FromHandle(hLayer)->AlterGeomFieldDefn(
1407 : iGeomField,
1408 : const_cast<const OGRGeomFieldDefn *>(
1409 33 : OGRGeomFieldDefn::FromHandle(hNewGeomFieldDefn)),
1410 33 : nFlags);
1411 : }
1412 :
1413 : /************************************************************************/
1414 : /* CreateGeomField() */
1415 : /************************************************************************/
1416 :
1417 0 : OGRErr OGRLayer::CreateGeomField(const OGRGeomFieldDefn *poField, int bApproxOK)
1418 :
1419 : {
1420 : (void)poField;
1421 : (void)bApproxOK;
1422 :
1423 0 : CPLError(CE_Failure, CPLE_NotSupported,
1424 : "CreateGeomField() not supported by this layer.\n");
1425 :
1426 0 : return OGRERR_UNSUPPORTED_OPERATION;
1427 : }
1428 :
1429 : /************************************************************************/
1430 : /* OGR_L_CreateGeomField() */
1431 : /************************************************************************/
1432 :
1433 140 : OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
1434 : int bApproxOK)
1435 :
1436 : {
1437 140 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1438 140 : VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1439 :
1440 : #ifdef OGRAPISPY_ENABLED
1441 140 : if (bOGRAPISpyEnabled)
1442 2 : OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
1443 : #endif
1444 :
1445 280 : return OGRLayer::FromHandle(hLayer)->CreateGeomField(
1446 140 : OGRGeomFieldDefn::FromHandle(hField), bApproxOK);
1447 : }
1448 :
1449 : /************************************************************************/
1450 : /* StartTransaction() */
1451 : /************************************************************************/
1452 :
1453 745 : OGRErr OGRLayer::StartTransaction()
1454 :
1455 : {
1456 745 : return OGRERR_NONE;
1457 : }
1458 :
1459 : /************************************************************************/
1460 : /* OGR_L_StartTransaction() */
1461 : /************************************************************************/
1462 :
1463 160 : OGRErr OGR_L_StartTransaction(OGRLayerH hLayer)
1464 :
1465 : {
1466 160 : VALIDATE_POINTER1(hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE);
1467 :
1468 : #ifdef OGRAPISPY_ENABLED
1469 160 : if (bOGRAPISpyEnabled)
1470 2 : OGRAPISpy_L_StartTransaction(hLayer);
1471 : #endif
1472 :
1473 160 : return OGRLayer::FromHandle(hLayer)->StartTransaction();
1474 : }
1475 :
1476 : /************************************************************************/
1477 : /* CommitTransaction() */
1478 : /************************************************************************/
1479 :
1480 699 : OGRErr OGRLayer::CommitTransaction()
1481 :
1482 : {
1483 699 : return OGRERR_NONE;
1484 : }
1485 :
1486 : /************************************************************************/
1487 : /* OGR_L_CommitTransaction() */
1488 : /************************************************************************/
1489 :
1490 140 : OGRErr OGR_L_CommitTransaction(OGRLayerH hLayer)
1491 :
1492 : {
1493 140 : VALIDATE_POINTER1(hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE);
1494 :
1495 : #ifdef OGRAPISPY_ENABLED
1496 140 : if (bOGRAPISpyEnabled)
1497 2 : OGRAPISpy_L_CommitTransaction(hLayer);
1498 : #endif
1499 :
1500 140 : return OGRLayer::FromHandle(hLayer)->CommitTransaction();
1501 : }
1502 :
1503 : /************************************************************************/
1504 : /* RollbackTransaction() */
1505 : /************************************************************************/
1506 :
1507 49 : OGRErr OGRLayer::RollbackTransaction()
1508 :
1509 : {
1510 49 : return OGRERR_UNSUPPORTED_OPERATION;
1511 : }
1512 :
1513 : /************************************************************************/
1514 : /* OGR_L_RollbackTransaction() */
1515 : /************************************************************************/
1516 :
1517 26 : OGRErr OGR_L_RollbackTransaction(OGRLayerH hLayer)
1518 :
1519 : {
1520 26 : VALIDATE_POINTER1(hLayer, "OGR_L_RollbackTransaction",
1521 : OGRERR_INVALID_HANDLE);
1522 :
1523 : #ifdef OGRAPISPY_ENABLED
1524 26 : if (bOGRAPISpyEnabled)
1525 2 : OGRAPISpy_L_RollbackTransaction(hLayer);
1526 : #endif
1527 :
1528 26 : return OGRLayer::FromHandle(hLayer)->RollbackTransaction();
1529 : }
1530 :
1531 : /************************************************************************/
1532 : /* OGR_L_GetLayerDefn() */
1533 : /************************************************************************/
1534 :
1535 132679 : OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
1536 :
1537 : {
1538 132679 : VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
1539 :
1540 : #ifdef OGRAPISPY_ENABLED
1541 132679 : if (bOGRAPISpyEnabled)
1542 15 : OGRAPISpy_L_GetLayerDefn(hLayer);
1543 : #endif
1544 :
1545 132679 : return OGRFeatureDefn::ToHandle(
1546 132679 : OGRLayer::FromHandle(hLayer)->GetLayerDefn());
1547 : }
1548 :
1549 : /************************************************************************/
1550 : /* OGR_L_FindFieldIndex() */
1551 : /************************************************************************/
1552 :
1553 2 : int OGR_L_FindFieldIndex(OGRLayerH hLayer, const char *pszFieldName,
1554 : int bExactMatch)
1555 :
1556 : {
1557 2 : VALIDATE_POINTER1(hLayer, "OGR_L_FindFieldIndex", -1);
1558 :
1559 : #ifdef OGRAPISPY_ENABLED
1560 2 : if (bOGRAPISpyEnabled)
1561 2 : OGRAPISpy_L_FindFieldIndex(hLayer, pszFieldName, bExactMatch);
1562 : #endif
1563 :
1564 4 : return OGRLayer::FromHandle(hLayer)->FindFieldIndex(pszFieldName,
1565 2 : bExactMatch);
1566 : }
1567 :
1568 : /************************************************************************/
1569 : /* FindFieldIndex() */
1570 : /************************************************************************/
1571 :
1572 80 : int OGRLayer::FindFieldIndex(const char *pszFieldName,
1573 : CPL_UNUSED int bExactMatch)
1574 : {
1575 80 : return GetLayerDefn()->GetFieldIndex(pszFieldName);
1576 : }
1577 :
1578 : /************************************************************************/
1579 : /* GetSpatialRef() */
1580 : /************************************************************************/
1581 :
1582 430614 : const OGRSpatialReference *OGRLayer::GetSpatialRef() const
1583 : {
1584 430614 : const auto poLayerDefn = GetLayerDefn();
1585 430614 : if (poLayerDefn->GetGeomFieldCount() > 0)
1586 : return const_cast<OGRSpatialReference *>(
1587 430150 : poLayerDefn->GetGeomFieldDefn(0)->GetSpatialRef());
1588 : else
1589 464 : return nullptr;
1590 : }
1591 :
1592 : /************************************************************************/
1593 : /* OGR_L_GetSpatialRef() */
1594 : /************************************************************************/
1595 :
1596 1071 : OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
1597 :
1598 : {
1599 1071 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
1600 :
1601 : #ifdef OGRAPISPY_ENABLED
1602 1071 : if (bOGRAPISpyEnabled)
1603 2 : OGRAPISpy_L_GetSpatialRef(hLayer);
1604 : #endif
1605 :
1606 1071 : return OGRSpatialReference::ToHandle(const_cast<OGRSpatialReference *>(
1607 1071 : OGRLayer::FromHandle(hLayer)->GetSpatialRef()));
1608 : }
1609 :
1610 : /************************************************************************/
1611 : /* OGR_L_TestCapability() */
1612 : /************************************************************************/
1613 :
1614 922 : int OGR_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
1615 :
1616 : {
1617 922 : VALIDATE_POINTER1(hLayer, "OGR_L_TestCapability", 0);
1618 922 : VALIDATE_POINTER1(pszCap, "OGR_L_TestCapability", 0);
1619 :
1620 : #ifdef OGRAPISPY_ENABLED
1621 922 : if (bOGRAPISpyEnabled)
1622 2 : OGRAPISpy_L_TestCapability(hLayer, pszCap);
1623 : #endif
1624 :
1625 922 : return OGRLayer::FromHandle(hLayer)->TestCapability(pszCap);
1626 : }
1627 :
1628 : /************************************************************************/
1629 : /* GetSpatialFilter() */
1630 : /************************************************************************/
1631 :
1632 423 : OGRGeometry *OGRLayer::GetSpatialFilter()
1633 :
1634 : {
1635 423 : return m_poFilterGeom;
1636 : }
1637 :
1638 : /************************************************************************/
1639 : /* OGR_L_GetSpatialFilter() */
1640 : /************************************************************************/
1641 :
1642 5 : OGRGeometryH OGR_L_GetSpatialFilter(OGRLayerH hLayer)
1643 :
1644 : {
1645 5 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialFilter", nullptr);
1646 :
1647 : #ifdef OGRAPISPY_ENABLED
1648 5 : if (bOGRAPISpyEnabled)
1649 2 : OGRAPISpy_L_GetSpatialFilter(hLayer);
1650 : #endif
1651 :
1652 5 : return OGRGeometry::ToHandle(
1653 10 : OGRLayer::FromHandle(hLayer)->GetSpatialFilter());
1654 : }
1655 :
1656 : /************************************************************************/
1657 : /* ValidateGeometryFieldIndexForSetSpatialFilter() */
1658 : /************************************************************************/
1659 :
1660 : //! @cond Doxygen_Suppress
1661 53561 : bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
1662 : int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
1663 : {
1664 53561 : if (iGeomField == 0 && poGeomIn == nullptr &&
1665 0 : GetLayerDefn()->GetGeomFieldCount() == 0)
1666 : {
1667 : // Setting a null spatial filter on geometry field idx 0
1668 : // when there are no geometry field can't harm, and is accepted silently
1669 : // for backward compatibility with existing practice.
1670 : }
1671 106881 : else if (iGeomField < 0 ||
1672 53320 : iGeomField >= GetLayerDefn()->GetGeomFieldCount())
1673 : {
1674 563 : if (iGeomField == 0)
1675 : {
1676 79 : CPLError(
1677 : CE_Failure, CPLE_AppDefined,
1678 : bIsSelectLayer
1679 : ? "Cannot set spatial filter: no geometry field selected."
1680 : : "Cannot set spatial filter: no geometry field present in "
1681 : "layer.");
1682 : }
1683 : else
1684 : {
1685 484 : CPLError(CE_Failure, CPLE_AppDefined,
1686 : "Cannot set spatial filter on non-existing geometry field "
1687 : "of index %d.",
1688 : iGeomField);
1689 : }
1690 563 : return false;
1691 : }
1692 52998 : return true;
1693 : }
1694 :
1695 : //! @endcond
1696 :
1697 : /************************************************************************/
1698 : /* SetSpatialFilter() */
1699 : /************************************************************************/
1700 :
1701 : /**
1702 : \brief Set a new spatial filter.
1703 :
1704 : This method set the geometry to be used as a spatial filter when
1705 : fetching features via the GetNextFeature() method. Only features that
1706 : geometrically intersect the filter geometry will be returned.
1707 :
1708 : Currently this test is may be inaccurately implemented, but it is
1709 : guaranteed that all features whose envelope (as returned by
1710 : OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
1711 : will be returned. This can result in more shapes being returned that
1712 : should strictly be the case.
1713 :
1714 : Starting with GDAL 2.3, features with null or empty geometries will never
1715 : be considered as matching a spatial filter.
1716 :
1717 : This method makes an internal copy of the passed geometry. The
1718 : passed geometry remains the responsibility of the caller, and may
1719 : be safely destroyed.
1720 :
1721 : For the time being the passed filter geometry should be in the same
1722 : SRS as the layer (as returned by OGRLayer::GetSpatialRef()). In the
1723 : future this may be generalized.
1724 :
1725 : This method is the same as the C function OGR_L_SetSpatialFilter().
1726 :
1727 : @param poFilter the geometry to use as a filtering region. NULL may
1728 : be passed indicating that the current spatial filter should be cleared,
1729 : but no new one instituted.
1730 : */
1731 :
1732 6986 : OGRErr OGRLayer::SetSpatialFilter(const OGRGeometry *poFilter)
1733 :
1734 : {
1735 6986 : return SetSpatialFilter(0, poFilter);
1736 : }
1737 :
1738 : /**
1739 : \brief Set a new spatial filter.
1740 :
1741 : This method set the geometry to be used as a spatial filter when
1742 : fetching features via the GetNextFeature() method. Only features that
1743 : geometrically intersect the filter geometry will be returned.
1744 :
1745 : Currently this test is may be inaccurately implemented, but it is
1746 : guaranteed that all features who's envelope (as returned by
1747 : OGRGeometry::getEnvelope()) overlaps the envelope of the spatial filter
1748 : will be returned. This can result in more shapes being returned that
1749 : should strictly be the case.
1750 :
1751 : This method makes an internal copy of the passed geometry. The
1752 : passed geometry remains the responsibility of the caller, and may
1753 : be safely destroyed.
1754 :
1755 : For the time being the passed filter geometry should be in the same
1756 : SRS as the geometry field definition it corresponds to (as returned by
1757 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). In the
1758 : future this may be generalized.
1759 :
1760 : Note that only the last spatial filter set is applied, even if several
1761 : successive calls are done with different iGeomField values.
1762 :
1763 : This method is the same as the C function OGR_L_SetSpatialFilterEx().
1764 :
1765 : @param iGeomField index of the geometry field on which the spatial filter
1766 : operates.
1767 : @param poFilter the geometry to use as a filtering region. NULL may
1768 : be passed indicating that the current spatial filter should be cleared,
1769 : but no new one instituted.
1770 :
1771 : @since GDAL 1.11
1772 : */
1773 :
1774 66281 : OGRErr OGRLayer::SetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
1775 :
1776 : {
1777 66281 : if (iGeomField == 0)
1778 : {
1779 116854 : if (poFilter &&
1780 52066 : !ValidateGeometryFieldIndexForSetSpatialFilter(0, poFilter))
1781 : {
1782 79 : return OGRERR_FAILURE;
1783 : }
1784 : }
1785 : else
1786 : {
1787 1493 : if (!ValidateGeometryFieldIndexForSetSpatialFilter(iGeomField,
1788 : poFilter))
1789 : {
1790 484 : return OGRERR_FAILURE;
1791 : }
1792 : }
1793 :
1794 65718 : return ISetSpatialFilter(iGeomField, poFilter);
1795 : }
1796 :
1797 : /************************************************************************/
1798 : /* ISetSpatialFilter() */
1799 : /************************************************************************/
1800 :
1801 : /**
1802 : \brief Set a new spatial filter.
1803 :
1804 : Virtual method implemented by drivers since 3.11. In previous versions,
1805 : SetSpatialFilter() / SetSpatialFilterRect() itself was the virtual method.
1806 :
1807 : Driver implementations, when wanting to call the base method, must take
1808 : care of calling OGRLayer::ISetSpatialFilter() (and note the public method without
1809 : the leading I).
1810 :
1811 : @param iGeomField index of the geometry field on which the spatial filter
1812 : operates.
1813 : @param poFilter the geometry to use as a filtering region. NULL may
1814 : be passed indicating that the current spatial filter should be cleared,
1815 : but no new one instituted.
1816 :
1817 : @since GDAL 3.11
1818 : */
1819 :
1820 37260 : OGRErr OGRLayer::ISetSpatialFilter(int iGeomField, const OGRGeometry *poFilter)
1821 :
1822 : {
1823 37260 : m_iGeomFieldFilter = iGeomField;
1824 37260 : if (InstallFilter(poFilter))
1825 28795 : ResetReading();
1826 37260 : return OGRERR_NONE;
1827 : }
1828 :
1829 : /************************************************************************/
1830 : /* OGR_L_SetSpatialFilter() */
1831 : /************************************************************************/
1832 :
1833 : /**
1834 : \brief Set a new spatial filter.
1835 :
1836 : This function set the geometry to be used as a spatial filter when
1837 : fetching features via the OGR_L_GetNextFeature() function. Only
1838 : features that geometrically intersect the filter geometry will be
1839 : returned.
1840 :
1841 : Currently this test is may be inaccurately implemented, but it is
1842 : guaranteed that all features whose envelope (as returned by
1843 : OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
1844 : will be returned. This can result in more shapes being returned that
1845 : should strictly be the case.
1846 :
1847 : Starting with GDAL 2.3, features with null or empty geometries will never
1848 : be considered as matching a spatial filter.
1849 :
1850 : This function makes an internal copy of the passed geometry. The
1851 : passed geometry remains the responsibility of the caller, and may
1852 : be safely destroyed.
1853 :
1854 : For the time being the passed filter geometry should be in the same
1855 : SRS as the layer (as returned by OGR_L_GetSpatialRef()). In the
1856 : future this may be generalized.
1857 :
1858 : This function is the same as the C++ method OGRLayer::SetSpatialFilter.
1859 :
1860 : @param hLayer handle to the layer on which to set the spatial filter.
1861 : @param hGeom handle to the geometry to use as a filtering region. NULL may
1862 : be passed indicating that the current spatial filter should be cleared,
1863 : but no new one instituted.
1864 :
1865 : */
1866 :
1867 648 : void OGR_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
1868 :
1869 : {
1870 648 : VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilter");
1871 :
1872 : #ifdef OGRAPISPY_ENABLED
1873 648 : if (bOGRAPISpyEnabled)
1874 4 : OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
1875 : #endif
1876 :
1877 1296 : OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
1878 648 : OGRGeometry::FromHandle(hGeom));
1879 : }
1880 :
1881 : /************************************************************************/
1882 : /* OGR_L_SetSpatialFilterEx() */
1883 : /************************************************************************/
1884 :
1885 : /**
1886 : \brief Set a new spatial filter.
1887 :
1888 : This function set the geometry to be used as a spatial filter when
1889 : fetching features via the OGR_L_GetNextFeature() function. Only
1890 : features that geometrically intersect the filter geometry will be
1891 : returned.
1892 :
1893 : Currently this test is may be inaccurately implemented, but it is
1894 : guaranteed that all features who's envelope (as returned by
1895 : OGR_G_GetEnvelope()) overlaps the envelope of the spatial filter
1896 : will be returned. This can result in more shapes being returned that
1897 : should strictly be the case.
1898 :
1899 : This function makes an internal copy of the passed geometry. The
1900 : passed geometry remains the responsibility of the caller, and may
1901 : be safely destroyed.
1902 :
1903 : For the time being the passed filter geometry should be in the same
1904 : SRS as the geometry field definition it corresponds to (as returned by
1905 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). In the
1906 : future this may be generalized.
1907 :
1908 : Note that only the last spatial filter set is applied, even if several
1909 : successive calls are done with different iGeomField values.
1910 :
1911 : This function is the same as the C++ method OGRLayer::SetSpatialFilter.
1912 :
1913 : @param hLayer handle to the layer on which to set the spatial filter.
1914 : @param iGeomField index of the geometry field on which the spatial filter
1915 : operates.
1916 : @param hGeom handle to the geometry to use as a filtering region. NULL may
1917 : be passed indicating that the current spatial filter should be cleared,
1918 : but no new one instituted.
1919 :
1920 : @since GDAL 1.11
1921 :
1922 : */
1923 :
1924 12 : void OGR_L_SetSpatialFilterEx(OGRLayerH hLayer, int iGeomField,
1925 : OGRGeometryH hGeom)
1926 :
1927 : {
1928 12 : VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterEx");
1929 :
1930 : #ifdef OGRAPISPY_ENABLED
1931 12 : if (bOGRAPISpyEnabled)
1932 2 : OGRAPISpy_L_SetSpatialFilterEx(hLayer, iGeomField, hGeom);
1933 : #endif
1934 :
1935 24 : OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
1936 12 : iGeomField, OGRGeometry::FromHandle(hGeom));
1937 : }
1938 :
1939 : /************************************************************************/
1940 : /* SetSpatialFilterRect() */
1941 : /************************************************************************/
1942 :
1943 : /**
1944 : \brief Set a new rectangular spatial filter.
1945 :
1946 : This method set rectangle to be used as a spatial filter when
1947 : fetching features via the GetNextFeature() method. Only features that
1948 : geometrically intersect the given rectangle will be returned.
1949 :
1950 : The x/y values should be in the same coordinate system as the layer as
1951 : a whole (as returned by OGRLayer::GetSpatialRef()). Internally this
1952 : method is normally implemented as creating a 5 vertex closed rectangular
1953 : polygon and passing it to OGRLayer::SetSpatialFilter(). It exists as
1954 : a convenience.
1955 :
1956 : The only way to clear a spatial filter set with this method is to
1957 : call OGRLayer::SetSpatialFilter(NULL).
1958 :
1959 : This method is the same as the C function OGR_L_SetSpatialFilterRect().
1960 :
1961 : @param dfMinX the minimum X coordinate for the rectangular region.
1962 : @param dfMinY the minimum Y coordinate for the rectangular region.
1963 : @param dfMaxX the maximum X coordinate for the rectangular region.
1964 : @param dfMaxY the maximum Y coordinate for the rectangular region.
1965 :
1966 : */
1967 :
1968 48042 : OGRErr OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY,
1969 : double dfMaxX, double dfMaxY)
1970 :
1971 : {
1972 48042 : return SetSpatialFilterRect(0, dfMinX, dfMinY, dfMaxX, dfMaxY);
1973 : }
1974 :
1975 : /**
1976 : \brief Set a new rectangular spatial filter.
1977 :
1978 : This method set rectangle to be used as a spatial filter when
1979 : fetching features via the GetNextFeature() method. Only features that
1980 : geometrically intersect the given rectangle will be returned.
1981 :
1982 : The x/y values should be in the same coordinate system as as the geometry
1983 : field definition it corresponds to (as returned by
1984 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
1985 : method is normally implemented as creating a 5 vertex closed rectangular
1986 : polygon and passing it to OGRLayer::SetSpatialFilter(). It exists as
1987 : a convenience.
1988 :
1989 : The only way to clear a spatial filter set with this method is to
1990 : call OGRLayer::SetSpatialFilter(NULL).
1991 :
1992 : This method is the same as the C function OGR_L_SetSpatialFilterRectEx().
1993 :
1994 : @param iGeomField index of the geometry field on which the spatial filter
1995 : operates.
1996 : @param dfMinX the minimum X coordinate for the rectangular region.
1997 : @param dfMinY the minimum Y coordinate for the rectangular region.
1998 : @param dfMaxX the maximum X coordinate for the rectangular region.
1999 : @param dfMaxY the maximum Y coordinate for the rectangular region.
2000 :
2001 : @since GDAL 1.11
2002 : */
2003 :
2004 48096 : OGRErr OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
2005 : double dfMinY, double dfMaxX,
2006 : double dfMaxY)
2007 :
2008 : {
2009 96192 : auto poRing = std::make_unique<OGRLinearRing>();
2010 96192 : OGRPolygon oPoly;
2011 :
2012 48096 : poRing->addPoint(dfMinX, dfMinY);
2013 48096 : poRing->addPoint(dfMinX, dfMaxY);
2014 48096 : poRing->addPoint(dfMaxX, dfMaxY);
2015 48096 : poRing->addPoint(dfMaxX, dfMinY);
2016 48096 : poRing->addPoint(dfMinX, dfMinY);
2017 :
2018 48096 : oPoly.addRing(std::move(poRing));
2019 :
2020 96192 : return SetSpatialFilter(iGeomField, &oPoly);
2021 : }
2022 :
2023 : /************************************************************************/
2024 : /* OGR_L_SetSpatialFilterRect() */
2025 : /************************************************************************/
2026 :
2027 : /**
2028 : \brief Set a new rectangular spatial filter.
2029 :
2030 : This method set rectangle to be used as a spatial filter when
2031 : fetching features via the OGR_L_GetNextFeature() method. Only features that
2032 : geometrically intersect the given rectangle will be returned.
2033 :
2034 : The x/y values should be in the same coordinate system as the layer as
2035 : a whole (as returned by OGRLayer::GetSpatialRef()). Internally this
2036 : method is normally implemented as creating a 5 vertex closed rectangular
2037 : polygon and passing it to OGRLayer::SetSpatialFilter(). It exists as
2038 : a convenience.
2039 :
2040 : The only way to clear a spatial filter set with this method is to
2041 : call OGRLayer::SetSpatialFilter(NULL).
2042 :
2043 : This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
2044 :
2045 : @param hLayer handle to the layer on which to set the spatial filter.
2046 : @param dfMinX the minimum X coordinate for the rectangular region.
2047 : @param dfMinY the minimum Y coordinate for the rectangular region.
2048 : @param dfMaxX the maximum X coordinate for the rectangular region.
2049 : @param dfMaxY the maximum Y coordinate for the rectangular region.
2050 :
2051 : */
2052 :
2053 47749 : void OGR_L_SetSpatialFilterRect(OGRLayerH hLayer, double dfMinX, double dfMinY,
2054 : double dfMaxX, double dfMaxY)
2055 :
2056 : {
2057 47749 : VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRect");
2058 :
2059 : #ifdef OGRAPISPY_ENABLED
2060 47749 : if (bOGRAPISpyEnabled)
2061 2 : OGRAPISpy_L_SetSpatialFilterRect(hLayer, dfMinX, dfMinY, dfMaxX,
2062 : dfMaxY);
2063 : #endif
2064 :
2065 47749 : OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(dfMinX, dfMinY, dfMaxX,
2066 : dfMaxY);
2067 : }
2068 :
2069 : /************************************************************************/
2070 : /* OGR_L_SetSpatialFilterRectEx() */
2071 : /************************************************************************/
2072 :
2073 : /**
2074 : \brief Set a new rectangular spatial filter.
2075 :
2076 : This method set rectangle to be used as a spatial filter when
2077 : fetching features via the OGR_L_GetNextFeature() method. Only features that
2078 : geometrically intersect the given rectangle will be returned.
2079 :
2080 : The x/y values should be in the same coordinate system as as the geometry
2081 : field definition it corresponds to (as returned by
2082 : GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(iGeomField)->GetSpatialRef()). Internally this
2083 : method is normally implemented as creating a 5 vertex closed rectangular
2084 : polygon and passing it to OGRLayer::SetSpatialFilter(). It exists as
2085 : a convenience.
2086 :
2087 : The only way to clear a spatial filter set with this method is to
2088 : call OGRLayer::SetSpatialFilter(NULL).
2089 :
2090 : This method is the same as the C++ method OGRLayer::SetSpatialFilterRect().
2091 :
2092 : @param hLayer handle to the layer on which to set the spatial filter.
2093 : @param iGeomField index of the geometry field on which the spatial filter
2094 : operates.
2095 : @param dfMinX the minimum X coordinate for the rectangular region.
2096 : @param dfMinY the minimum Y coordinate for the rectangular region.
2097 : @param dfMaxX the maximum X coordinate for the rectangular region.
2098 : @param dfMaxY the maximum Y coordinate for the rectangular region.
2099 :
2100 : @since GDAL 1.11
2101 : */
2102 :
2103 15 : void OGR_L_SetSpatialFilterRectEx(OGRLayerH hLayer, int iGeomField,
2104 : double dfMinX, double dfMinY, double dfMaxX,
2105 : double dfMaxY)
2106 :
2107 : {
2108 15 : VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilterRectEx");
2109 :
2110 : #ifdef OGRAPISPY_ENABLED
2111 15 : if (bOGRAPISpyEnabled)
2112 2 : OGRAPISpy_L_SetSpatialFilterRectEx(hLayer, iGeomField, dfMinX, dfMinY,
2113 : dfMaxX, dfMaxY);
2114 : #endif
2115 :
2116 15 : OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect(iGeomField, dfMinX,
2117 : dfMinY, dfMaxX, dfMaxY);
2118 : }
2119 :
2120 : /************************************************************************/
2121 : /* InstallFilter() */
2122 : /* */
2123 : /* This method is only intended to be used from within */
2124 : /* drivers, normally from the SetSpatialFilter() method. */
2125 : /* It installs a filter, and also tests it to see if it is */
2126 : /* rectangular. If so, it this is kept track of alongside the */
2127 : /* filter geometry itself so we can do cheaper comparisons in */
2128 : /* the FilterGeometry() call. */
2129 : /* */
2130 : /* Returns TRUE if the newly installed filter differs in some */
2131 : /* way from the current one. */
2132 : /************************************************************************/
2133 :
2134 : //! @cond Doxygen_Suppress
2135 64847 : int OGRLayer::InstallFilter(const OGRGeometry *poFilter)
2136 :
2137 : {
2138 64847 : if (m_poFilterGeom == poFilter)
2139 10608 : return FALSE;
2140 :
2141 : /* -------------------------------------------------------------------- */
2142 : /* Replace the existing filter. */
2143 : /* -------------------------------------------------------------------- */
2144 54239 : if (m_poFilterGeom != nullptr)
2145 : {
2146 51329 : delete m_poFilterGeom;
2147 51329 : m_poFilterGeom = nullptr;
2148 : }
2149 :
2150 54239 : if (m_pPreparedFilterGeom != nullptr)
2151 : {
2152 51329 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
2153 51329 : m_pPreparedFilterGeom = nullptr;
2154 : }
2155 :
2156 54239 : if (poFilter != nullptr)
2157 52204 : m_poFilterGeom = poFilter->clone();
2158 :
2159 54239 : m_bFilterIsEnvelope = FALSE;
2160 :
2161 54239 : if (m_poFilterGeom == nullptr)
2162 2035 : return TRUE;
2163 :
2164 52204 : m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
2165 :
2166 : /* Compile geometry filter as a prepared geometry */
2167 52204 : m_pPreparedFilterGeom =
2168 52204 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
2169 :
2170 52204 : m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
2171 :
2172 52204 : return TRUE;
2173 : }
2174 :
2175 : //! @endcond
2176 :
2177 : /************************************************************************/
2178 : /* DoesGeometryHavePointInEnvelope() */
2179 : /************************************************************************/
2180 :
2181 5521 : static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
2182 : const OGREnvelope &sEnvelope)
2183 : {
2184 5521 : const OGRLineString *poLS = nullptr;
2185 :
2186 5521 : switch (wkbFlatten(poGeometry->getGeometryType()))
2187 : {
2188 36 : case wkbPoint:
2189 : {
2190 36 : const auto poPoint = poGeometry->toPoint();
2191 36 : const double x = poPoint->getX();
2192 36 : const double y = poPoint->getY();
2193 31 : return (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
2194 67 : x <= sEnvelope.MaxX && y <= sEnvelope.MaxY);
2195 : }
2196 :
2197 394 : case wkbLineString:
2198 394 : poLS = poGeometry->toLineString();
2199 394 : break;
2200 :
2201 4350 : case wkbPolygon:
2202 : {
2203 4350 : const OGRPolygon *poPoly = poGeometry->toPolygon();
2204 4350 : poLS = poPoly->getExteriorRing();
2205 4350 : break;
2206 : }
2207 :
2208 500 : case wkbMultiPoint:
2209 : case wkbMultiLineString:
2210 : case wkbMultiPolygon:
2211 : case wkbGeometryCollection:
2212 : {
2213 732 : for (const auto &poSubGeom : *(poGeometry->toGeometryCollection()))
2214 : {
2215 646 : if (DoesGeometryHavePointInEnvelope(poSubGeom, sEnvelope))
2216 414 : return true;
2217 : }
2218 86 : return false;
2219 : }
2220 :
2221 241 : default:
2222 241 : return false;
2223 : }
2224 :
2225 4744 : if (poLS != nullptr)
2226 : {
2227 4744 : const int nNumPoints = poLS->getNumPoints();
2228 56500 : for (int i = 0; i < nNumPoints; i++)
2229 : {
2230 55398 : const double x = poLS->getX(i);
2231 55398 : const double y = poLS->getY(i);
2232 55398 : if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
2233 22074 : x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
2234 : {
2235 3642 : return true;
2236 : }
2237 : }
2238 : }
2239 :
2240 1102 : return false;
2241 : }
2242 :
2243 : /************************************************************************/
2244 : /* FilterGeometry() */
2245 : /* */
2246 : /* Compare the passed in geometry to the currently installed */
2247 : /* filter. Optimize for case where filter is just an */
2248 : /* envelope. */
2249 : /************************************************************************/
2250 :
2251 : //! @cond Doxygen_Suppress
2252 475740 : int OGRLayer::FilterGeometry(const OGRGeometry *poGeometry)
2253 :
2254 : {
2255 : /* -------------------------------------------------------------------- */
2256 : /* In trivial cases of new filter or target geometry, we accept */
2257 : /* an intersection. No geometry is taken to mean "the whole */
2258 : /* world". */
2259 : /* -------------------------------------------------------------------- */
2260 475740 : if (m_poFilterGeom == nullptr)
2261 376 : return TRUE;
2262 :
2263 475364 : if (poGeometry == nullptr || poGeometry->IsEmpty())
2264 303 : return FALSE;
2265 :
2266 : /* -------------------------------------------------------------------- */
2267 : /* Compute the target geometry envelope, and if there is no */
2268 : /* intersection between the envelopes we are sure not to have */
2269 : /* any intersection. */
2270 : /* -------------------------------------------------------------------- */
2271 475061 : OGREnvelope sGeomEnv;
2272 :
2273 475061 : poGeometry->getEnvelope(&sGeomEnv);
2274 :
2275 475061 : if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
2276 300819 : sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
2277 234625 : m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
2278 132101 : m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
2279 358812 : return FALSE;
2280 :
2281 : /* -------------------------------------------------------------------- */
2282 : /* If the filter geometry is its own envelope and if the */
2283 : /* envelope of the geometry is inside the filter geometry, */
2284 : /* the geometry itself is inside the filter geometry */
2285 : /* -------------------------------------------------------------------- */
2286 116249 : if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
2287 110994 : sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
2288 109729 : sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
2289 108881 : sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
2290 : {
2291 108502 : return TRUE;
2292 : }
2293 : else
2294 : {
2295 : // If the filter geometry is its own envelope and if the geometry has
2296 : // at least one point inside the filter geometry, the geometry itself
2297 : // intersects the filter geometry.
2298 7747 : if (m_bFilterIsEnvelope)
2299 : {
2300 4875 : if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
2301 3652 : return true;
2302 : }
2303 :
2304 : /* --------------------------------------------------------------------
2305 : */
2306 : /* Fallback to full intersect test (using GEOS) if we still */
2307 : /* don't know for sure. */
2308 : /* --------------------------------------------------------------------
2309 : */
2310 4095 : if (OGRGeometryFactory::haveGEOS())
2311 : {
2312 : // CPLDebug("OGRLayer", "GEOS intersection");
2313 4095 : if (m_pPreparedFilterGeom != nullptr)
2314 4095 : return OGRPreparedGeometryIntersects(
2315 : m_pPreparedFilterGeom,
2316 : OGRGeometry::ToHandle(
2317 4095 : const_cast<OGRGeometry *>(poGeometry)));
2318 : else
2319 0 : return m_poFilterGeom->Intersects(poGeometry);
2320 : }
2321 : else
2322 0 : return TRUE;
2323 : }
2324 : }
2325 :
2326 : /************************************************************************/
2327 : /* FilterWKBGeometry() */
2328 : /************************************************************************/
2329 :
2330 230 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
2331 : bool bEnvelopeAlreadySet,
2332 : OGREnvelope &sEnvelope) const
2333 : {
2334 230 : OGRPreparedGeometry *pPreparedFilterGeom = m_pPreparedFilterGeom;
2335 460 : bool bRet = FilterWKBGeometry(
2336 230 : pabyWKB, nWKBSize, bEnvelopeAlreadySet, sEnvelope, m_poFilterGeom,
2337 230 : m_bFilterIsEnvelope, m_sFilterEnvelope, pPreparedFilterGeom);
2338 230 : const_cast<OGRLayer *>(this)->m_pPreparedFilterGeom = pPreparedFilterGeom;
2339 230 : return bRet;
2340 : }
2341 :
2342 : /* static */
2343 334 : bool OGRLayer::FilterWKBGeometry(const GByte *pabyWKB, size_t nWKBSize,
2344 : bool bEnvelopeAlreadySet,
2345 : OGREnvelope &sEnvelope,
2346 : const OGRGeometry *poFilterGeom,
2347 : bool bFilterIsEnvelope,
2348 : const OGREnvelope &sFilterEnvelope,
2349 : OGRPreparedGeometry *&pPreparedFilterGeom)
2350 : {
2351 334 : if (!poFilterGeom)
2352 0 : return true;
2353 :
2354 636 : if ((bEnvelopeAlreadySet ||
2355 667 : OGRWKBGetBoundingBox(pabyWKB, nWKBSize, sEnvelope)) &&
2356 334 : sFilterEnvelope.Intersects(sEnvelope))
2357 : {
2358 161 : if (bFilterIsEnvelope && sFilterEnvelope.Contains(sEnvelope))
2359 : {
2360 98 : return true;
2361 : }
2362 : else
2363 : {
2364 126 : if (bFilterIsEnvelope &&
2365 63 : OGRWKBIntersectsPessimistic(pabyWKB, nWKBSize, sFilterEnvelope))
2366 : {
2367 51 : return true;
2368 : }
2369 12 : else if (OGRGeometryFactory::haveGEOS())
2370 : {
2371 12 : OGRGeometry *poGeom = nullptr;
2372 12 : int ret = FALSE;
2373 12 : if (OGRGeometryFactory::createFromWkb(pabyWKB, nullptr, &poGeom,
2374 12 : nWKBSize) == OGRERR_NONE)
2375 : {
2376 12 : if (!pPreparedFilterGeom)
2377 : {
2378 0 : pPreparedFilterGeom =
2379 0 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(
2380 : const_cast<OGRGeometry *>(poFilterGeom)));
2381 : }
2382 12 : if (pPreparedFilterGeom)
2383 12 : ret = OGRPreparedGeometryIntersects(
2384 : pPreparedFilterGeom,
2385 : OGRGeometry::ToHandle(
2386 : const_cast<OGRGeometry *>(poGeom)));
2387 : else
2388 0 : ret = poFilterGeom->Intersects(poGeom);
2389 : }
2390 12 : delete poGeom;
2391 12 : return CPL_TO_BOOL(ret);
2392 : }
2393 : else
2394 : {
2395 : // Assume intersection
2396 0 : return true;
2397 : }
2398 : }
2399 : }
2400 :
2401 172 : return false;
2402 : }
2403 :
2404 : /************************************************************************/
2405 : /* PrepareStartTransaction() */
2406 : /************************************************************************/
2407 :
2408 2856 : void OGRLayer::PrepareStartTransaction()
2409 : {
2410 2856 : m_apoFieldDefnChanges.clear();
2411 2856 : m_apoGeomFieldDefnChanges.clear();
2412 2856 : }
2413 :
2414 : /************************************************************************/
2415 : /* FinishRollbackTransaction() */
2416 : /************************************************************************/
2417 :
2418 171 : void OGRLayer::FinishRollbackTransaction(const std::string &osSavepointName)
2419 : {
2420 :
2421 : // Deleted fields can be safely removed from the storage after being restored.
2422 342 : std::vector<int> toBeRemoved;
2423 :
2424 171 : bool bSavepointFound = false;
2425 :
2426 : // Loop through all changed fields and reset them to their previous state.
2427 374 : for (int i = static_cast<int>(m_apoFieldDefnChanges.size()) - 1; i >= 0;
2428 : i--)
2429 : {
2430 203 : auto &oFieldChange = m_apoFieldDefnChanges[i];
2431 :
2432 203 : if (!osSavepointName.empty())
2433 : {
2434 172 : if (oFieldChange.osSavepointName == osSavepointName)
2435 : {
2436 60 : bSavepointFound = true;
2437 : }
2438 112 : else if (bSavepointFound)
2439 : {
2440 56 : continue;
2441 : }
2442 : }
2443 :
2444 147 : CPLAssert(oFieldChange.poFieldDefn);
2445 147 : const char *pszName = oFieldChange.poFieldDefn->GetNameRef();
2446 147 : const int iField = oFieldChange.iField;
2447 147 : if (iField >= 0)
2448 : {
2449 147 : switch (oFieldChange.eChangeType)
2450 : {
2451 128 : case FieldChangeType::DELETE_FIELD:
2452 : {
2453 : // Transfer ownership of the field to the layer
2454 256 : whileUnsealing(GetLayerDefn())
2455 128 : ->AddFieldDefn(std::move(oFieldChange.poFieldDefn));
2456 :
2457 : // Now move the field to the right place
2458 : // from the last position to its original position
2459 128 : const int iFieldCount = GetLayerDefn()->GetFieldCount();
2460 128 : CPLAssert(iFieldCount > 0);
2461 128 : CPLAssert(iFieldCount > iField);
2462 256 : std::vector<int> anOrder(iFieldCount);
2463 204 : for (int j = 0; j < iField; j++)
2464 : {
2465 76 : anOrder[j] = j;
2466 : }
2467 248 : for (int j = iField + 1; j < iFieldCount; j++)
2468 : {
2469 120 : anOrder[j] = j - 1;
2470 : }
2471 128 : anOrder[iField] = iFieldCount - 1;
2472 256 : if (OGRERR_NONE == whileUnsealing(GetLayerDefn())
2473 128 : ->ReorderFieldDefns(anOrder.data()))
2474 : {
2475 128 : toBeRemoved.push_back(i);
2476 : }
2477 : else
2478 : {
2479 0 : CPLError(CE_Failure, CPLE_AppDefined,
2480 : "Failed to restore deleted field %s", pszName);
2481 : }
2482 128 : break;
2483 : }
2484 8 : case FieldChangeType::ALTER_FIELD:
2485 : {
2486 : OGRFieldDefn *poFieldDefn =
2487 8 : GetLayerDefn()->GetFieldDefn(iField);
2488 8 : if (poFieldDefn)
2489 : {
2490 8 : *poFieldDefn = *oFieldChange.poFieldDefn;
2491 8 : toBeRemoved.push_back(i);
2492 : }
2493 : else
2494 : {
2495 0 : CPLError(CE_Failure, CPLE_AppDefined,
2496 : "Failed to restore altered field %s", pszName);
2497 : }
2498 8 : break;
2499 : }
2500 11 : case FieldChangeType::ADD_FIELD:
2501 : {
2502 : std::unique_ptr<OGRFieldDefn> poFieldDef =
2503 22 : GetLayerDefn()->StealFieldDefn(iField);
2504 11 : if (poFieldDef)
2505 : {
2506 11 : oFieldChange.poFieldDefn = std::move(poFieldDef);
2507 : }
2508 : else
2509 : {
2510 0 : CPLError(CE_Failure, CPLE_AppDefined,
2511 : "Failed to delete added field %s", pszName);
2512 : }
2513 11 : break;
2514 : }
2515 : }
2516 : }
2517 : else
2518 : {
2519 0 : CPLError(CE_Failure, CPLE_AppDefined,
2520 : "Failed to restore field %s (field not found at index %d)",
2521 : pszName, iField);
2522 : }
2523 : }
2524 :
2525 : // Remove from the storage the deleted fields that have been restored
2526 307 : for (const auto &i : toBeRemoved)
2527 : {
2528 136 : m_apoFieldDefnChanges.erase(m_apoFieldDefnChanges.begin() + i);
2529 : }
2530 :
2531 : /**********************************************************************/
2532 : /* Reset geometry fields to their previous state. */
2533 : /**********************************************************************/
2534 :
2535 171 : bSavepointFound = false;
2536 :
2537 : // Loop through all changed geometry fields and reset them to their previous state.
2538 171 : for (int i = static_cast<int>(m_apoGeomFieldDefnChanges.size()) - 1; i >= 0;
2539 : i--)
2540 : {
2541 0 : auto &oGeomFieldChange = m_apoGeomFieldDefnChanges[i];
2542 :
2543 0 : if (!osSavepointName.empty())
2544 : {
2545 0 : if (oGeomFieldChange.osSavepointName == osSavepointName)
2546 : {
2547 0 : bSavepointFound = true;
2548 : }
2549 0 : else if (bSavepointFound)
2550 : {
2551 0 : continue;
2552 : }
2553 : }
2554 0 : const char *pszName = oGeomFieldChange.poFieldDefn->GetNameRef();
2555 0 : const int iGeomField = oGeomFieldChange.iField;
2556 0 : if (iGeomField >= 0)
2557 : {
2558 0 : switch (oGeomFieldChange.eChangeType)
2559 : {
2560 0 : case FieldChangeType::DELETE_FIELD:
2561 : case FieldChangeType::ALTER_FIELD:
2562 : {
2563 : // Currently not handled by OGR for geometry fields
2564 0 : break;
2565 : }
2566 0 : case FieldChangeType::ADD_FIELD:
2567 : {
2568 : std::unique_ptr<OGRGeomFieldDefn> poGeomFieldDef =
2569 0 : GetLayerDefn()->StealGeomFieldDefn(
2570 0 : oGeomFieldChange.iField);
2571 0 : if (poGeomFieldDef)
2572 : {
2573 : oGeomFieldChange.poFieldDefn =
2574 0 : std::move(poGeomFieldDef);
2575 : }
2576 : else
2577 : {
2578 0 : CPLError(CE_Failure, CPLE_AppDefined,
2579 : "Failed to delete added geometry field %s",
2580 : pszName);
2581 : }
2582 0 : break;
2583 : }
2584 : }
2585 : }
2586 : else
2587 : {
2588 0 : CPLError(CE_Failure, CPLE_AppDefined,
2589 : "Failed to restore geometry field %s (field not found at "
2590 : "index %d)",
2591 : pszName, oGeomFieldChange.iField);
2592 : }
2593 : }
2594 171 : }
2595 :
2596 : //! @endcond
2597 :
2598 : /************************************************************************/
2599 : /* OGR_L_ResetReading() */
2600 : /************************************************************************/
2601 :
2602 17747 : void OGR_L_ResetReading(OGRLayerH hLayer)
2603 :
2604 : {
2605 17747 : VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
2606 :
2607 : #ifdef OGRAPISPY_ENABLED
2608 17747 : if (bOGRAPISpyEnabled)
2609 2 : OGRAPISpy_L_ResetReading(hLayer);
2610 : #endif
2611 :
2612 17747 : OGRLayer::FromHandle(hLayer)->ResetReading();
2613 : }
2614 :
2615 : /************************************************************************/
2616 : /* InitializeIndexSupport() */
2617 : /* */
2618 : /* This is only intended to be called by driver layer */
2619 : /* implementations but we don't make it protected so that the */
2620 : /* datasources can do it too if that is more appropriate. */
2621 : /************************************************************************/
2622 :
2623 : //! @cond Doxygen_Suppress
2624 : OGRErr
2625 665 : OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
2626 :
2627 : {
2628 : #ifdef HAVE_MITAB
2629 : OGRErr eErr;
2630 :
2631 665 : if (m_poAttrIndex != nullptr)
2632 496 : return OGRERR_NONE;
2633 :
2634 169 : m_poAttrIndex = OGRCreateDefaultLayerIndex();
2635 :
2636 169 : eErr = m_poAttrIndex->Initialize(pszFilename, this);
2637 169 : if (eErr != OGRERR_NONE)
2638 : {
2639 0 : delete m_poAttrIndex;
2640 0 : m_poAttrIndex = nullptr;
2641 : }
2642 :
2643 169 : return eErr;
2644 : #else
2645 : return OGRERR_FAILURE;
2646 : #endif
2647 : }
2648 :
2649 : //! @endcond
2650 :
2651 : /************************************************************************/
2652 : /* SyncToDisk() */
2653 : /************************************************************************/
2654 :
2655 5717 : OGRErr OGRLayer::SyncToDisk()
2656 :
2657 : {
2658 5717 : return OGRERR_NONE;
2659 : }
2660 :
2661 : /************************************************************************/
2662 : /* OGR_L_SyncToDisk() */
2663 : /************************************************************************/
2664 :
2665 251 : OGRErr OGR_L_SyncToDisk(OGRLayerH hLayer)
2666 :
2667 : {
2668 251 : VALIDATE_POINTER1(hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE);
2669 :
2670 : #ifdef OGRAPISPY_ENABLED
2671 251 : if (bOGRAPISpyEnabled)
2672 2 : OGRAPISpy_L_SyncToDisk(hLayer);
2673 : #endif
2674 :
2675 251 : return OGRLayer::FromHandle(hLayer)->SyncToDisk();
2676 : }
2677 :
2678 : /************************************************************************/
2679 : /* DeleteFeature() */
2680 : /************************************************************************/
2681 :
2682 318 : OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
2683 : {
2684 318 : return OGRERR_UNSUPPORTED_OPERATION;
2685 : }
2686 :
2687 : /************************************************************************/
2688 : /* OGR_L_DeleteFeature() */
2689 : /************************************************************************/
2690 :
2691 3355 : OGRErr OGR_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
2692 :
2693 : {
2694 3355 : VALIDATE_POINTER1(hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE);
2695 :
2696 : #ifdef OGRAPISPY_ENABLED
2697 3355 : if (bOGRAPISpyEnabled)
2698 2 : OGRAPISpy_L_DeleteFeature(hLayer, nFID);
2699 : #endif
2700 :
2701 3355 : return OGRLayer::FromHandle(hLayer)->DeleteFeature(nFID);
2702 : }
2703 :
2704 : /************************************************************************/
2705 : /* GetFeaturesRead() */
2706 : /************************************************************************/
2707 :
2708 : //! @cond Doxygen_Suppress
2709 0 : GIntBig OGRLayer::GetFeaturesRead()
2710 :
2711 : {
2712 0 : return m_nFeaturesRead;
2713 : }
2714 :
2715 : //! @endcond
2716 :
2717 : /************************************************************************/
2718 : /* OGR_L_GetFeaturesRead() */
2719 : /************************************************************************/
2720 :
2721 0 : GIntBig OGR_L_GetFeaturesRead(OGRLayerH hLayer)
2722 :
2723 : {
2724 0 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeaturesRead", 0);
2725 :
2726 0 : return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
2727 : }
2728 :
2729 : /************************************************************************/
2730 : /* GetFIDColumn */
2731 : /************************************************************************/
2732 :
2733 7730 : const char *OGRLayer::GetFIDColumn() const
2734 :
2735 : {
2736 7730 : return "";
2737 : }
2738 :
2739 : /************************************************************************/
2740 : /* OGR_L_GetFIDColumn() */
2741 : /************************************************************************/
2742 :
2743 398 : const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
2744 :
2745 : {
2746 398 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
2747 :
2748 : #ifdef OGRAPISPY_ENABLED
2749 398 : if (bOGRAPISpyEnabled)
2750 2 : OGRAPISpy_L_GetFIDColumn(hLayer);
2751 : #endif
2752 :
2753 398 : return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
2754 : }
2755 :
2756 : /************************************************************************/
2757 : /* GetGeometryColumn() */
2758 : /************************************************************************/
2759 :
2760 3596 : const char *OGRLayer::GetGeometryColumn() const
2761 :
2762 : {
2763 3596 : const auto poLayerDefn = GetLayerDefn();
2764 3596 : if (poLayerDefn->GetGeomFieldCount() > 0)
2765 3516 : return poLayerDefn->GetGeomFieldDefn(0)->GetNameRef();
2766 : else
2767 80 : return "";
2768 : }
2769 :
2770 : /************************************************************************/
2771 : /* OGR_L_GetGeometryColumn() */
2772 : /************************************************************************/
2773 :
2774 693 : const char *OGR_L_GetGeometryColumn(OGRLayerH hLayer)
2775 :
2776 : {
2777 693 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryColumn", nullptr);
2778 :
2779 : #ifdef OGRAPISPY_ENABLED
2780 693 : if (bOGRAPISpyEnabled)
2781 2 : OGRAPISpy_L_GetGeometryColumn(hLayer);
2782 : #endif
2783 :
2784 693 : return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
2785 : }
2786 :
2787 : /************************************************************************/
2788 : /* GetStyleTable() */
2789 : /************************************************************************/
2790 :
2791 1048 : OGRStyleTable *OGRLayer::GetStyleTable()
2792 : {
2793 1048 : 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 1045 : void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
2812 : {
2813 1045 : if (m_poStyleTable)
2814 0 : delete m_poStyleTable;
2815 1045 : if (poStyleTable)
2816 1 : m_poStyleTable = poStyleTable->Clone();
2817 1045 : }
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 1503000 : const char *OGRLayer::GetName() const
2864 :
2865 : {
2866 1503000 : return GetLayerDefn()->GetName();
2867 : }
2868 :
2869 : /************************************************************************/
2870 : /* OGR_L_GetName() */
2871 : /************************************************************************/
2872 :
2873 1275 : const char *OGR_L_GetName(OGRLayerH hLayer)
2874 :
2875 : {
2876 1275 : VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
2877 :
2878 : #ifdef OGRAPISPY_ENABLED
2879 1275 : if (bOGRAPISpyEnabled)
2880 2 : OGRAPISpy_L_GetName(hLayer);
2881 : #endif
2882 :
2883 1275 : return OGRLayer::FromHandle(hLayer)->GetName();
2884 : }
2885 :
2886 : /************************************************************************/
2887 : /* GetGeomType() */
2888 : /************************************************************************/
2889 :
2890 218494 : OGRwkbGeometryType OGRLayer::GetGeomType() const
2891 : {
2892 218494 : const OGRFeatureDefn *poLayerDefn = GetLayerDefn();
2893 218494 : if (poLayerDefn == nullptr)
2894 : {
2895 0 : CPLDebug("OGR", "GetLayerType() returns NULL !");
2896 0 : return wkbUnknown;
2897 : }
2898 218494 : return poLayerDefn->GetGeomType();
2899 : }
2900 :
2901 : /************************************************************************/
2902 : /* OGR_L_GetGeomType() */
2903 : /************************************************************************/
2904 :
2905 1119 : OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
2906 :
2907 : {
2908 1119 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
2909 :
2910 : #ifdef OGRAPISPY_ENABLED
2911 1119 : if (bOGRAPISpyEnabled)
2912 2 : OGRAPISpy_L_GetGeomType(hLayer);
2913 : #endif
2914 :
2915 1119 : OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
2916 1119 : if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
2917 : {
2918 1 : eType = OGR_GT_GetLinear(eType);
2919 : }
2920 1119 : return eType;
2921 : }
2922 :
2923 : /************************************************************************/
2924 : /* SetIgnoredFields() */
2925 : /************************************************************************/
2926 :
2927 8659 : OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
2928 : {
2929 8659 : OGRFeatureDefn *poDefn = GetLayerDefn();
2930 :
2931 : // first set everything as *not* ignored
2932 63973 : for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
2933 : {
2934 55314 : poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
2935 : }
2936 20037 : for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
2937 : {
2938 11378 : poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
2939 : }
2940 8659 : poDefn->SetStyleIgnored(FALSE);
2941 :
2942 : // ignore some fields
2943 16268 : for (const char *pszFieldName : cpl::Iterate(papszFields))
2944 : {
2945 : // check special fields
2946 7609 : if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
2947 156 : poDefn->SetGeometryIgnored(TRUE);
2948 7453 : else if (EQUAL(pszFieldName, "OGR_STYLE"))
2949 13 : poDefn->SetStyleIgnored(TRUE);
2950 : else
2951 : {
2952 : // check ordinary fields
2953 7440 : int iField = poDefn->GetFieldIndex(pszFieldName);
2954 7440 : if (iField == -1)
2955 : {
2956 : // check geometry field
2957 1679 : iField = poDefn->GetGeomFieldIndex(pszFieldName);
2958 1679 : if (iField == -1)
2959 : {
2960 0 : return OGRERR_FAILURE;
2961 : }
2962 : else
2963 1679 : poDefn->GetGeomFieldDefn(iField)->SetIgnored(TRUE);
2964 : }
2965 : else
2966 5761 : poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
2967 : }
2968 : }
2969 :
2970 8659 : 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 30 : OGRErr OGR_L_Rename(OGRLayerH hLayer, const char *pszNewName)
3042 :
3043 : {
3044 30 : VALIDATE_POINTER1(hLayer, "OGR_L_Rename", OGRERR_INVALID_HANDLE);
3045 30 : VALIDATE_POINTER1(pszNewName, "OGR_L_Rename", OGRERR_FAILURE);
3046 :
3047 30 : 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 37194 : 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 37194 : OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
6054 37194 : : m_poPrivate(new OGRLayer::FeatureIterator::Private())
6055 : {
6056 37194 : m_poPrivate->m_poLayer = poLayer;
6057 37194 : if (bStart)
6058 : {
6059 18597 : 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 18596 : m_poPrivate->m_poLayer->ResetReading();
6069 37192 : m_poPrivate->m_poFeature.reset(
6070 18596 : m_poPrivate->m_poLayer->GetNextFeature());
6071 18596 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
6072 18596 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
6073 : }
6074 : }
6075 37194 : }
6076 :
6077 : /************************************************************************/
6078 : /* ~OGRLayer::FeatureIterator::FeatureIterator() */
6079 : /************************************************************************/
6080 :
6081 37194 : OGRLayer::FeatureIterator::~FeatureIterator()
6082 : {
6083 37194 : if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
6084 37193 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
6085 37194 : }
6086 :
6087 : /************************************************************************/
6088 : /* operator*() */
6089 : /************************************************************************/
6090 :
6091 166309 : OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
6092 : {
6093 166309 : return m_poPrivate->m_poFeature;
6094 : }
6095 :
6096 : /************************************************************************/
6097 : /* operator++() */
6098 : /************************************************************************/
6099 :
6100 165594 : OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
6101 : {
6102 165594 : m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
6103 165594 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
6104 165594 : return *this;
6105 : }
6106 :
6107 : /************************************************************************/
6108 : /* operator!=() */
6109 : /************************************************************************/
6110 :
6111 184191 : bool OGRLayer::FeatureIterator::operator!=(
6112 : const OGRLayer::FeatureIterator &it) const
6113 : {
6114 184191 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
6115 : }
6116 :
6117 : /************************************************************************/
6118 : /* begin() */
6119 : /************************************************************************/
6120 :
6121 18597 : OGRLayer::FeatureIterator OGRLayer::begin()
6122 : {
6123 18597 : return {this, true};
6124 : }
6125 :
6126 : /************************************************************************/
6127 : /* end() */
6128 : /************************************************************************/
6129 :
6130 18597 : OGRLayer::FeatureIterator OGRLayer::end()
6131 : {
6132 18597 : 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 183 : OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
6347 : {
6348 183 : static OGRLayer::GetSupportedSRSListRetType empty;
6349 183 : 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 262 : GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
6522 : {
6523 262 : VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
6524 262 : return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
6525 : }
|