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