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 69517 : OGRLayer::OGRLayer()
34 69517 : : 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 139034 : m_nFeaturesRead(0)
40 : {
41 69517 : }
42 :
43 : /************************************************************************/
44 : /* ~OGRLayer() */
45 : /************************************************************************/
46 :
47 69500 : OGRLayer::~OGRLayer()
48 :
49 : {
50 69500 : if (m_poStyleTable)
51 : {
52 11 : delete m_poStyleTable;
53 11 : m_poStyleTable = nullptr;
54 : }
55 :
56 69500 : if (m_poAttrIndex != nullptr)
57 : {
58 164 : delete m_poAttrIndex;
59 164 : m_poAttrIndex = nullptr;
60 : }
61 :
62 69500 : if (m_poAttrQuery != nullptr)
63 : {
64 631 : delete m_poAttrQuery;
65 631 : m_poAttrQuery = nullptr;
66 : }
67 :
68 69500 : CPLFree(m_pszAttrQueryString);
69 :
70 69500 : if (m_poFilterGeom)
71 : {
72 841 : delete m_poFilterGeom;
73 841 : m_poFilterGeom = nullptr;
74 : }
75 :
76 69500 : if (m_pPreparedFilterGeom != nullptr)
77 : {
78 841 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
79 841 : m_pPreparedFilterGeom = nullptr;
80 : }
81 :
82 69500 : if (m_poSharedArrowArrayStreamPrivateData != nullptr)
83 : {
84 677 : m_poSharedArrowArrayStreamPrivateData->m_poLayer = nullptr;
85 : }
86 69500 : }
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 13823 : GIntBig OGRLayer::GetFeatureCount(int bForce)
159 :
160 : {
161 13823 : if (!bForce)
162 1 : return -1;
163 :
164 13822 : GIntBig nFeatureCount = 0;
165 55650 : for (auto &&poFeature : *this)
166 : {
167 41828 : CPL_IGNORE_RET_VAL(poFeature.get());
168 41828 : nFeatureCount++;
169 : }
170 13822 : ResetReading();
171 :
172 13822 : return nFeatureCount;
173 : }
174 :
175 : /************************************************************************/
176 : /* OGR_L_GetFeatureCount() */
177 : /************************************************************************/
178 :
179 36792 : GIntBig OGR_L_GetFeatureCount(OGRLayerH hLayer, int bForce)
180 :
181 : {
182 36792 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeatureCount", 0);
183 :
184 : #ifdef OGRAPISPY_ENABLED
185 36792 : if (bOGRAPISpyEnabled)
186 2 : OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
187 : #endif
188 :
189 36792 : return OGRLayer::FromHandle(hLayer)->GetFeatureCount(bForce);
190 : }
191 :
192 : /************************************************************************/
193 : /* GetExtent() */
194 : /************************************************************************/
195 :
196 439 : OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, int bForce)
197 :
198 : {
199 439 : return GetExtentInternal(0, psExtent, bForce);
200 : }
201 :
202 1487 : OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
203 :
204 : {
205 1487 : if (iGeomField == 0)
206 966 : 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 1019 : OGRErr OGRLayer::GetExtentInternal(int iGeomField, OGREnvelope *psExtent,
289 : int bForce)
290 :
291 : {
292 1019 : psExtent->MinX = 0.0;
293 1019 : psExtent->MaxX = 0.0;
294 1019 : psExtent->MinY = 0.0;
295 1019 : 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 1428 : if (iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
302 409 : 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 409 : 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 408 : OGREnvelope oEnv;
324 408 : bool bExtentSet = false;
325 :
326 9575 : 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 408 : ResetReading();
356 :
357 408 : return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
358 : }
359 :
360 : //! @endcond
361 :
362 : /************************************************************************/
363 : /* OGR_L_GetExtent() */
364 : /************************************************************************/
365 :
366 58 : OGRErr OGR_L_GetExtent(OGRLayerH hLayer, OGREnvelope *psExtent, int bForce)
367 :
368 : {
369 58 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE);
370 :
371 : #ifdef OGRAPISPY_ENABLED
372 58 : if (bOGRAPISpyEnabled)
373 0 : OGRAPISpy_L_GetExtent(hLayer, bForce);
374 : #endif
375 :
376 58 : return OGRLayer::FromHandle(hLayer)->GetExtent(psExtent, bForce);
377 : }
378 :
379 : /************************************************************************/
380 : /* OGR_L_GetExtentEx() */
381 : /************************************************************************/
382 :
383 370 : OGRErr OGR_L_GetExtentEx(OGRLayerH hLayer, int iGeomField,
384 : OGREnvelope *psExtent, int bForce)
385 :
386 : {
387 370 : VALIDATE_POINTER1(hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE);
388 :
389 : #ifdef OGRAPISPY_ENABLED
390 370 : if (bOGRAPISpyEnabled)
391 4 : OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
392 : #endif
393 :
394 740 : return OGRLayer::FromHandle(hLayer)->GetExtent(iGeomField, psExtent,
395 370 : 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 14753 : OGRErr OGRLayer::SetAttributeFilter(const char *pszQuery)
422 :
423 : {
424 14753 : CPLFree(m_pszAttrQueryString);
425 14753 : m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
426 :
427 : /* -------------------------------------------------------------------- */
428 : /* Are we just clearing any existing query? */
429 : /* -------------------------------------------------------------------- */
430 14753 : if (pszQuery == nullptr || strlen(pszQuery) == 0)
431 : {
432 9791 : if (m_poAttrQuery)
433 : {
434 2824 : delete m_poAttrQuery;
435 2824 : m_poAttrQuery = nullptr;
436 2824 : ResetReading();
437 : }
438 9791 : return OGRERR_NONE;
439 : }
440 :
441 : /* -------------------------------------------------------------------- */
442 : /* Or are we installing a new query? */
443 : /* -------------------------------------------------------------------- */
444 : OGRErr eErr;
445 :
446 4962 : if (!m_poAttrQuery)
447 3513 : m_poAttrQuery = new OGRFeatureQuery();
448 :
449 4962 : eErr = m_poAttrQuery->Compile(this, pszQuery);
450 4962 : if (eErr != OGRERR_NONE)
451 : {
452 2 : delete m_poAttrQuery;
453 2 : m_poAttrQuery = nullptr;
454 : }
455 :
456 4962 : ResetReading();
457 :
458 4962 : return eErr;
459 : }
460 :
461 : /************************************************************************/
462 : /* ContainGeomSpecialField() */
463 : /************************************************************************/
464 :
465 274 : static int ContainGeomSpecialField(swq_expr_node *expr, int nLayerFieldCount)
466 : {
467 274 : 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 217 : 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 217 : return FALSE;
486 : }
487 :
488 : /************************************************************************/
489 : /* AttributeFilterEvaluationNeedsGeometry() */
490 : /************************************************************************/
491 :
492 : //! @cond Doxygen_Suppress
493 60 : int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
494 : {
495 60 : if (!m_poAttrQuery)
496 0 : return FALSE;
497 :
498 : swq_expr_node *expr =
499 60 : static_cast<swq_expr_node *>(m_poAttrQuery->GetSWQExpr());
500 60 : int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
501 :
502 60 : return ContainGeomSpecialField(expr, nLayerFieldCount);
503 : }
504 :
505 : //! @endcond
506 :
507 : /************************************************************************/
508 : /* OGR_L_SetAttributeFilter() */
509 : /************************************************************************/
510 :
511 1444 : OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char *pszQuery)
512 :
513 : {
514 1444 : VALIDATE_POINTER1(hLayer, "OGR_L_SetAttributeFilter",
515 : OGRERR_INVALID_HANDLE);
516 :
517 : #ifdef OGRAPISPY_ENABLED
518 1444 : if (bOGRAPISpyEnabled)
519 4 : OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
520 : #endif
521 :
522 1444 : 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 2532 : OGRFeatureH OGR_L_GetFeature(OGRLayerH hLayer, GIntBig nFeatureId)
566 :
567 : {
568 2532 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeature", nullptr);
569 :
570 : #ifdef OGRAPISPY_ENABLED
571 2532 : if (bOGRAPISpyEnabled)
572 2 : OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
573 : #endif
574 :
575 2532 : return OGRFeature::ToHandle(
576 5064 : 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 83010 : OGRFeatureH OGR_L_GetNextFeature(OGRLayerH hLayer)
626 :
627 : {
628 83010 : VALIDATE_POINTER1(hLayer, "OGR_L_GetNextFeature", nullptr);
629 :
630 : #ifdef OGRAPISPY_ENABLED
631 83010 : if (bOGRAPISpyEnabled)
632 8 : OGRAPISpy_L_GetNextFeature(hLayer);
633 : #endif
634 :
635 83010 : return OGRFeature::ToHandle(OGRLayer::FromHandle(hLayer)->GetNextFeature());
636 : }
637 :
638 : /************************************************************************/
639 : /* ConvertGeomsIfNecessary() */
640 : /************************************************************************/
641 :
642 942402 : void OGRLayer::ConvertGeomsIfNecessary(OGRFeature *poFeature)
643 : {
644 942402 : if (!m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled)
645 : {
646 : // One time initialization
647 9219 : m_poPrivate->m_bConvertGeomsIfNecessaryAlreadyCalled = true;
648 9219 : m_poPrivate->m_bSupportsCurve =
649 9219 : CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
650 9219 : m_poPrivate->m_bSupportsM =
651 9219 : CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
652 9219 : 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 1791340 : if (!m_poPrivate->m_bSupportsCurve || !m_poPrivate->m_bSupportsM ||
673 848943 : m_poPrivate->m_bApplyGeomSetPrecision)
674 : {
675 93461 : const auto poFeatureDefn = GetLayerDefn();
676 93461 : const int nGeomFieldCount = poFeatureDefn->GetGeomFieldCount();
677 186137 : for (int i = 0; i < nGeomFieldCount; i++)
678 : {
679 92676 : OGRGeometry *poGeom = poFeature->GetGeomFieldRef(i);
680 92676 : if (poGeom)
681 : {
682 108373 : if (!m_poPrivate->m_bSupportsM &&
683 18789 : OGR_GT_HasM(poGeom->getGeometryType()))
684 : {
685 1 : poGeom->setMeasured(FALSE);
686 : }
687 :
688 178923 : if (!m_poPrivate->m_bSupportsCurve &&
689 89339 : 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 89584 : 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 942402 : }
722 :
723 : /************************************************************************/
724 : /* SetFeature() */
725 : /************************************************************************/
726 :
727 3580 : OGRErr OGRLayer::SetFeature(OGRFeature *poFeature)
728 :
729 : {
730 3580 : ConvertGeomsIfNecessary(poFeature);
731 3580 : 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 938711 : OGRErr OGRLayer::CreateFeature(OGRFeature *poFeature)
768 :
769 : {
770 938711 : ConvertGeomsIfNecessary(poFeature);
771 938711 : 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 287632 : OGRErr OGR_L_CreateFeature(OGRLayerH hLayer, OGRFeatureH hFeat)
789 :
790 : {
791 287632 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
792 287632 : VALIDATE_POINTER1(hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE);
793 :
794 : #ifdef OGRAPISPY_ENABLED
795 287632 : if (bOGRAPISpyEnabled)
796 5 : OGRAPISpy_L_CreateFeature(hLayer, hFeat);
797 : #endif
798 :
799 287632 : return OGRLayer::FromHandle(hLayer)->CreateFeature(
800 287632 : 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 77860 : OGRErr OGR_L_CreateField(OGRLayerH hLayer, OGRFieldDefnH hField, int bApproxOK)
960 :
961 : {
962 77860 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
963 77860 : VALIDATE_POINTER1(hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE);
964 :
965 : #ifdef OGRAPISPY_ENABLED
966 77860 : if (bOGRAPISpyEnabled)
967 6 : OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
968 : #endif
969 :
970 155720 : return OGRLayer::FromHandle(hLayer)->CreateField(
971 77860 : 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 75 : OGRErr OGR_L_DeleteField(OGRLayerH hLayer, int iField)
994 :
995 : {
996 75 : VALIDATE_POINTER1(hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE);
997 :
998 : #ifdef OGRAPISPY_ENABLED
999 75 : if (bOGRAPISpyEnabled)
1000 2 : OGRAPISpy_L_DeleteField(hLayer, iField);
1001 : #endif
1002 :
1003 75 : 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 122 : OGRErr OGR_L_AlterFieldDefn(OGRLayerH hLayer, int iField,
1133 : OGRFieldDefnH hNewFieldDefn, int nFlags)
1134 :
1135 : {
1136 122 : VALIDATE_POINTER1(hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE);
1137 122 : VALIDATE_POINTER1(hNewFieldDefn, "OGR_L_AlterFieldDefn",
1138 : OGRERR_INVALID_HANDLE);
1139 :
1140 : #ifdef OGRAPISPY_ENABLED
1141 122 : if (bOGRAPISpyEnabled)
1142 2 : OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
1143 : #endif
1144 :
1145 244 : return OGRLayer::FromHandle(hLayer)->AlterFieldDefn(
1146 122 : 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 119 : OGRErr OGR_L_CreateGeomField(OGRLayerH hLayer, OGRGeomFieldDefnH hField,
1206 : int bApproxOK)
1207 :
1208 : {
1209 119 : VALIDATE_POINTER1(hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1210 119 : VALIDATE_POINTER1(hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE);
1211 :
1212 : #ifdef OGRAPISPY_ENABLED
1213 119 : if (bOGRAPISpyEnabled)
1214 2 : OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
1215 : #endif
1216 :
1217 238 : return OGRLayer::FromHandle(hLayer)->CreateGeomField(
1218 119 : OGRGeomFieldDefn::FromHandle(hField), bApproxOK);
1219 : }
1220 :
1221 : /************************************************************************/
1222 : /* StartTransaction() */
1223 : /************************************************************************/
1224 :
1225 627 : OGRErr OGRLayer::StartTransaction()
1226 :
1227 : {
1228 627 : return OGRERR_NONE;
1229 : }
1230 :
1231 : /************************************************************************/
1232 : /* OGR_L_StartTransaction() */
1233 : /************************************************************************/
1234 :
1235 158 : OGRErr OGR_L_StartTransaction(OGRLayerH hLayer)
1236 :
1237 : {
1238 158 : VALIDATE_POINTER1(hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE);
1239 :
1240 : #ifdef OGRAPISPY_ENABLED
1241 158 : if (bOGRAPISpyEnabled)
1242 2 : OGRAPISpy_L_StartTransaction(hLayer);
1243 : #endif
1244 :
1245 158 : return OGRLayer::FromHandle(hLayer)->StartTransaction();
1246 : }
1247 :
1248 : /************************************************************************/
1249 : /* CommitTransaction() */
1250 : /************************************************************************/
1251 :
1252 579 : OGRErr OGRLayer::CommitTransaction()
1253 :
1254 : {
1255 579 : return OGRERR_NONE;
1256 : }
1257 :
1258 : /************************************************************************/
1259 : /* OGR_L_CommitTransaction() */
1260 : /************************************************************************/
1261 :
1262 138 : OGRErr OGR_L_CommitTransaction(OGRLayerH hLayer)
1263 :
1264 : {
1265 138 : VALIDATE_POINTER1(hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE);
1266 :
1267 : #ifdef OGRAPISPY_ENABLED
1268 138 : if (bOGRAPISpyEnabled)
1269 2 : OGRAPISpy_L_CommitTransaction(hLayer);
1270 : #endif
1271 :
1272 138 : 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 130089 : OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH hLayer)
1308 :
1309 : {
1310 130089 : VALIDATE_POINTER1(hLayer, "OGR_L_GetLayerDefn", nullptr);
1311 :
1312 : #ifdef OGRAPISPY_ENABLED
1313 130089 : if (bOGRAPISpyEnabled)
1314 15 : OGRAPISpy_L_GetLayerDefn(hLayer);
1315 : #endif
1316 :
1317 130089 : return OGRFeatureDefn::ToHandle(
1318 260178 : 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 109 : int OGRLayer::FindFieldIndex(const char *pszFieldName,
1345 : CPL_UNUSED int bExactMatch)
1346 : {
1347 109 : return GetLayerDefn()->GetFieldIndex(pszFieldName);
1348 : }
1349 :
1350 : /************************************************************************/
1351 : /* GetSpatialRef() */
1352 : /************************************************************************/
1353 :
1354 424453 : OGRSpatialReference *OGRLayer::GetSpatialRef()
1355 : {
1356 424453 : if (GetLayerDefn()->GetGeomFieldCount() > 0)
1357 : return const_cast<OGRSpatialReference *>(
1358 423977 : GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef());
1359 : else
1360 476 : return nullptr;
1361 : }
1362 :
1363 : /************************************************************************/
1364 : /* OGR_L_GetSpatialRef() */
1365 : /************************************************************************/
1366 :
1367 1027 : OGRSpatialReferenceH OGR_L_GetSpatialRef(OGRLayerH hLayer)
1368 :
1369 : {
1370 1027 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSpatialRef", nullptr);
1371 :
1372 : #ifdef OGRAPISPY_ENABLED
1373 1027 : if (bOGRAPISpyEnabled)
1374 2 : OGRAPISpy_L_GetSpatialRef(hLayer);
1375 : #endif
1376 :
1377 1027 : return OGRSpatialReference::ToHandle(
1378 2054 : OGRLayer::FromHandle(hLayer)->GetSpatialRef());
1379 : }
1380 :
1381 : /************************************************************************/
1382 : /* OGR_L_TestCapability() */
1383 : /************************************************************************/
1384 :
1385 823 : int OGR_L_TestCapability(OGRLayerH hLayer, const char *pszCap)
1386 :
1387 : {
1388 823 : VALIDATE_POINTER1(hLayer, "OGR_L_TestCapability", 0);
1389 823 : VALIDATE_POINTER1(pszCap, "OGR_L_TestCapability", 0);
1390 :
1391 : #ifdef OGRAPISPY_ENABLED
1392 823 : if (bOGRAPISpyEnabled)
1393 2 : OGRAPISpy_L_TestCapability(hLayer, pszCap);
1394 : #endif
1395 :
1396 823 : return OGRLayer::FromHandle(hLayer)->TestCapability(pszCap);
1397 : }
1398 :
1399 : /************************************************************************/
1400 : /* GetSpatialFilter() */
1401 : /************************************************************************/
1402 :
1403 389 : OGRGeometry *OGRLayer::GetSpatialFilter()
1404 :
1405 : {
1406 389 : 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 30936 : bool OGRLayer::ValidateGeometryFieldIndexForSetSpatialFilter(
1433 : int iGeomField, const OGRGeometry *poGeomIn, bool bIsSelectLayer)
1434 : {
1435 31348 : 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 61620 : else if (iGeomField < 0 ||
1443 30706 : 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 30439 : return true;
1464 : }
1465 :
1466 : //! @endcond
1467 :
1468 : /************************************************************************/
1469 : /* SetSpatialFilter() */
1470 : /************************************************************************/
1471 :
1472 36172 : void OGRLayer::SetSpatialFilter(OGRGeometry *poGeomIn)
1473 :
1474 : {
1475 36172 : if (poGeomIn && !ValidateGeometryFieldIndexForSetSpatialFilter(0, poGeomIn))
1476 77 : return;
1477 :
1478 36095 : m_iGeomFieldFilter = 0;
1479 36095 : if (InstallFilter(poGeomIn))
1480 28209 : ResetReading();
1481 : }
1482 :
1483 6905 : void OGRLayer::SetSpatialFilter(int iGeomField, OGRGeometry *poGeomIn)
1484 :
1485 : {
1486 6905 : if (iGeomField == 0)
1487 : {
1488 8116 : if (poGeomIn &&
1489 1963 : !ValidateGeometryFieldIndexForSetSpatialFilter(0, poGeomIn))
1490 0 : return;
1491 :
1492 6153 : m_iGeomFieldFilter = iGeomField;
1493 6153 : 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 647 : void OGR_L_SetSpatialFilter(OGRLayerH hLayer, OGRGeometryH hGeom)
1512 :
1513 : {
1514 647 : VALIDATE_POINTER0(hLayer, "OGR_L_SetSpatialFilter");
1515 :
1516 : #ifdef OGRAPISPY_ENABLED
1517 647 : if (bOGRAPISpyEnabled)
1518 4 : OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
1519 : #endif
1520 :
1521 1294 : OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
1522 647 : 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 48039 : void OGRLayer::SetSpatialFilterRect(double dfMinX, double dfMinY, double dfMaxX,
1549 : double dfMaxY)
1550 :
1551 : {
1552 48039 : SetSpatialFilterRect(0, dfMinX, dfMinY, dfMaxX, dfMaxY);
1553 48039 : }
1554 :
1555 48098 : void OGRLayer::SetSpatialFilterRect(int iGeomField, double dfMinX,
1556 : double dfMinY, double dfMaxX, double dfMaxY)
1557 :
1558 : {
1559 96196 : OGRLinearRing oRing;
1560 96196 : OGRPolygon oPoly;
1561 :
1562 48098 : oRing.addPoint(dfMinX, dfMinY);
1563 48098 : oRing.addPoint(dfMinX, dfMaxY);
1564 48098 : oRing.addPoint(dfMaxX, dfMaxY);
1565 48098 : oRing.addPoint(dfMaxX, dfMinY);
1566 48098 : oRing.addPoint(dfMinX, dfMinY);
1567 :
1568 48098 : oPoly.addRing(&oRing);
1569 :
1570 48098 : if (iGeomField == 0)
1571 : /* for drivers that only overload SetSpatialFilter(OGRGeometry*) */
1572 48080 : SetSpatialFilter(&oPoly);
1573 : else
1574 18 : SetSpatialFilter(iGeomField, &oPoly);
1575 48098 : }
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 64133 : int OGRLayer::InstallFilter(OGRGeometry *poFilter)
1634 :
1635 : {
1636 64133 : if (m_poFilterGeom == poFilter)
1637 10220 : return FALSE;
1638 :
1639 : /* -------------------------------------------------------------------- */
1640 : /* Replace the existing filter. */
1641 : /* -------------------------------------------------------------------- */
1642 53913 : if (m_poFilterGeom != nullptr)
1643 : {
1644 51072 : delete m_poFilterGeom;
1645 51072 : m_poFilterGeom = nullptr;
1646 : }
1647 :
1648 53913 : if (m_pPreparedFilterGeom != nullptr)
1649 : {
1650 51072 : OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
1651 51072 : m_pPreparedFilterGeom = nullptr;
1652 : }
1653 :
1654 53913 : if (poFilter != nullptr)
1655 51913 : m_poFilterGeom = poFilter->clone();
1656 :
1657 53913 : m_bFilterIsEnvelope = FALSE;
1658 :
1659 53913 : if (m_poFilterGeom == nullptr)
1660 2000 : return TRUE;
1661 :
1662 51913 : m_poFilterGeom->getEnvelope(&m_sFilterEnvelope);
1663 :
1664 : /* Compile geometry filter as a prepared geometry */
1665 51913 : m_pPreparedFilterGeom =
1666 51913 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
1667 :
1668 51913 : m_bFilterIsEnvelope = m_poFilterGeom->IsRectangle();
1669 :
1670 51913 : return TRUE;
1671 : }
1672 :
1673 : //! @endcond
1674 :
1675 : /************************************************************************/
1676 : /* DoesGeometryHavePointInEnvelope() */
1677 : /************************************************************************/
1678 :
1679 5240 : static bool DoesGeometryHavePointInEnvelope(const OGRGeometry *poGeometry,
1680 : const OGREnvelope &sEnvelope)
1681 : {
1682 5240 : const OGRLineString *poLS = nullptr;
1683 :
1684 5240 : 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 4107 : case wkbPolygon:
1700 : {
1701 4107 : const OGRPolygon *poPoly = poGeometry->toPolygon();
1702 4107 : poLS = poPoly->getExteriorRing();
1703 4107 : 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 4500 : if (poLS != nullptr)
1724 : {
1725 4500 : const int nNumPoints = poLS->getNumPoints();
1726 52297 : for (int i = 0; i < nNumPoints; i++)
1727 : {
1728 51244 : const double x = poLS->getX(i);
1729 51244 : const double y = poLS->getY(i);
1730 51244 : if (x >= sEnvelope.MinX && y >= sEnvelope.MinY &&
1731 20372 : x <= sEnvelope.MaxX && y <= sEnvelope.MaxY)
1732 : {
1733 3447 : return true;
1734 : }
1735 : }
1736 : }
1737 :
1738 1053 : 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 448635 : 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 448635 : if (m_poFilterGeom == nullptr)
1759 376 : return TRUE;
1760 :
1761 448259 : 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 447958 : OGREnvelope sGeomEnv;
1770 :
1771 447958 : poGeometry->getEnvelope(&sGeomEnv);
1772 :
1773 447958 : if (sGeomEnv.MaxX < m_sFilterEnvelope.MinX ||
1774 294830 : sGeomEnv.MaxY < m_sFilterEnvelope.MinY ||
1775 228632 : m_sFilterEnvelope.MaxX < sGeomEnv.MinX ||
1776 130265 : m_sFilterEnvelope.MaxY < sGeomEnv.MinY)
1777 333798 : 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 114160 : if (m_bFilterIsEnvelope && sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
1785 110883 : sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
1786 109671 : sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
1787 108838 : sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
1788 : {
1789 108449 : 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 5711 : if (m_bFilterIsEnvelope)
1797 : {
1798 4631 : if (DoesGeometryHavePointInEnvelope(poGeometry, m_sFilterEnvelope))
1799 3457 : 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 2254 : if (OGRGeometryFactory::haveGEOS())
1809 : {
1810 : // CPLDebug("OGRLayer", "GEOS intersection");
1811 2254 : if (m_pPreparedFilterGeom != nullptr)
1812 2254 : return OGRPreparedGeometryIntersects(
1813 : m_pPreparedFilterGeom,
1814 : OGRGeometry::ToHandle(
1815 2254 : 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 636 : if ((bEnvelopeAlreadySet ||
1853 667 : OGRWKBGetBoundingBox(pabyWKB, nWKBSize, sEnvelope)) &&
1854 334 : sFilterEnvelope.Intersects(sEnvelope))
1855 : {
1856 160 : if (bFilterIsEnvelope && sFilterEnvelope.Contains(sEnvelope))
1857 : {
1858 97 : 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 : /************************************************************************/
1903 : /* PrepareStartTransaction() */
1904 : /************************************************************************/
1905 :
1906 232 : void OGRLayer::PrepareStartTransaction()
1907 : {
1908 232 : m_apoFieldDefnChanges.clear();
1909 232 : m_apoGeomFieldDefnChanges.clear();
1910 232 : }
1911 :
1912 : /************************************************************************/
1913 : /* FinishRollbackTransaction() */
1914 : /************************************************************************/
1915 :
1916 54 : void OGRLayer::FinishRollbackTransaction()
1917 : {
1918 :
1919 : // Deleted fields can be safely removed from the storage after being restored.
1920 108 : std::vector<int> toBeRemoved;
1921 :
1922 : // Loop through all changed fields and reset them to their previous state.
1923 71 : for (int i = static_cast<int>(m_apoFieldDefnChanges.size()) - 1; i >= 0;
1924 : i--)
1925 : {
1926 17 : auto &oFieldChange = m_apoFieldDefnChanges[i];
1927 17 : CPLAssert(oFieldChange.poFieldDefn);
1928 17 : const char *pszName = oFieldChange.poFieldDefn->GetNameRef();
1929 17 : const int iField = oFieldChange.iField;
1930 17 : if (iField >= 0)
1931 : {
1932 17 : switch (oFieldChange.eChangeType)
1933 : {
1934 6 : case FieldChangeType::DELETE_FIELD:
1935 : {
1936 : // Transfer ownership of the field to the layer
1937 12 : whileUnsealing(GetLayerDefn())
1938 6 : ->AddFieldDefn(std::move(oFieldChange.poFieldDefn));
1939 :
1940 : // Now move the field to the right place
1941 : // from the last position to its original position
1942 6 : const int iFieldCount = GetLayerDefn()->GetFieldCount();
1943 6 : CPLAssert(iFieldCount > 0);
1944 6 : CPLAssert(iFieldCount > iField);
1945 12 : std::vector<int> anOrder(iFieldCount);
1946 8 : for (int j = 0; j < iField; j++)
1947 : {
1948 2 : anOrder[j] = j;
1949 : }
1950 10 : for (int j = iField + 1; j < iFieldCount; j++)
1951 : {
1952 4 : anOrder[j] = j - 1;
1953 : }
1954 6 : anOrder[iField] = iFieldCount - 1;
1955 12 : if (OGRERR_NONE == whileUnsealing(GetLayerDefn())
1956 6 : ->ReorderFieldDefns(anOrder.data()))
1957 : {
1958 6 : toBeRemoved.push_back(i);
1959 : }
1960 : else
1961 : {
1962 0 : CPLError(CE_Failure, CPLE_AppDefined,
1963 : "Failed to restore deleted field %s", pszName);
1964 : }
1965 6 : break;
1966 : }
1967 4 : case FieldChangeType::ALTER_FIELD:
1968 : {
1969 : OGRFieldDefn *poFieldDefn =
1970 4 : GetLayerDefn()->GetFieldDefn(iField);
1971 4 : if (poFieldDefn)
1972 : {
1973 4 : *poFieldDefn = *oFieldChange.poFieldDefn;
1974 4 : toBeRemoved.push_back(i);
1975 : }
1976 : else
1977 : {
1978 0 : CPLError(CE_Failure, CPLE_AppDefined,
1979 : "Failed to restore altered field %s", pszName);
1980 : }
1981 4 : break;
1982 : }
1983 7 : case FieldChangeType::ADD_FIELD:
1984 : {
1985 : std::unique_ptr<OGRFieldDefn> poFieldDef =
1986 14 : GetLayerDefn()->StealFieldDefn(iField);
1987 7 : if (poFieldDef)
1988 : {
1989 7 : oFieldChange.poFieldDefn = std::move(poFieldDef);
1990 : }
1991 : else
1992 : {
1993 0 : CPLError(CE_Failure, CPLE_AppDefined,
1994 : "Failed to delete added field %s", pszName);
1995 : }
1996 7 : break;
1997 : }
1998 : }
1999 : }
2000 : else
2001 : {
2002 0 : CPLError(CE_Failure, CPLE_AppDefined,
2003 : "Failed to restore field %s (field not found at index %d)",
2004 : pszName, iField);
2005 : }
2006 : }
2007 :
2008 : // Remove from the storage the deleted fields that have been restored
2009 64 : for (const auto &i : toBeRemoved)
2010 : {
2011 10 : m_apoFieldDefnChanges.erase(m_apoFieldDefnChanges.begin() + i);
2012 : }
2013 :
2014 : // Loop through all changed geometry fields and reset them to their previous state.
2015 55 : for (int i = static_cast<int>(m_apoGeomFieldDefnChanges.size()) - 1; i >= 0;
2016 : i--)
2017 : {
2018 1 : auto &oGeomFieldChange = m_apoGeomFieldDefnChanges[i];
2019 1 : const char *pszName = oGeomFieldChange.poFieldDefn->GetNameRef();
2020 1 : const int iGeomField = oGeomFieldChange.iField;
2021 1 : if (iGeomField >= 0)
2022 : {
2023 1 : switch (oGeomFieldChange.eChangeType)
2024 : {
2025 0 : case FieldChangeType::DELETE_FIELD:
2026 : case FieldChangeType::ALTER_FIELD:
2027 : {
2028 : // Currently not handled by OGR for geometry fields
2029 0 : break;
2030 : }
2031 1 : case FieldChangeType::ADD_FIELD:
2032 : {
2033 : std::unique_ptr<OGRGeomFieldDefn> poGeomFieldDef =
2034 1 : GetLayerDefn()->StealGeomFieldDefn(
2035 2 : oGeomFieldChange.iField);
2036 1 : if (poGeomFieldDef)
2037 : {
2038 : oGeomFieldChange.poFieldDefn =
2039 1 : std::move(poGeomFieldDef);
2040 : }
2041 : else
2042 : {
2043 0 : CPLError(CE_Failure, CPLE_AppDefined,
2044 : "Failed to delete added geometry field %s",
2045 : pszName);
2046 : }
2047 1 : break;
2048 : }
2049 : }
2050 : }
2051 : else
2052 : {
2053 0 : CPLError(CE_Failure, CPLE_AppDefined,
2054 : "Failed to restore geometry field %s (field not found at "
2055 : "index %d)",
2056 : pszName, oGeomFieldChange.iField);
2057 : }
2058 : }
2059 54 : }
2060 :
2061 : //! @endcond
2062 :
2063 : /************************************************************************/
2064 : /* OGR_L_ResetReading() */
2065 : /************************************************************************/
2066 :
2067 17667 : void OGR_L_ResetReading(OGRLayerH hLayer)
2068 :
2069 : {
2070 17667 : VALIDATE_POINTER0(hLayer, "OGR_L_ResetReading");
2071 :
2072 : #ifdef OGRAPISPY_ENABLED
2073 17667 : if (bOGRAPISpyEnabled)
2074 2 : OGRAPISpy_L_ResetReading(hLayer);
2075 : #endif
2076 :
2077 17667 : OGRLayer::FromHandle(hLayer)->ResetReading();
2078 : }
2079 :
2080 : /************************************************************************/
2081 : /* InitializeIndexSupport() */
2082 : /* */
2083 : /* This is only intended to be called by driver layer */
2084 : /* implementations but we don't make it protected so that the */
2085 : /* datasources can do it too if that is more appropriate. */
2086 : /************************************************************************/
2087 :
2088 : //! @cond Doxygen_Suppress
2089 : OGRErr
2090 648 : OGRLayer::InitializeIndexSupport([[maybe_unused]] const char *pszFilename)
2091 :
2092 : {
2093 : #ifdef HAVE_MITAB
2094 : OGRErr eErr;
2095 :
2096 648 : if (m_poAttrIndex != nullptr)
2097 484 : return OGRERR_NONE;
2098 :
2099 164 : m_poAttrIndex = OGRCreateDefaultLayerIndex();
2100 :
2101 164 : eErr = m_poAttrIndex->Initialize(pszFilename, this);
2102 164 : if (eErr != OGRERR_NONE)
2103 : {
2104 0 : delete m_poAttrIndex;
2105 0 : m_poAttrIndex = nullptr;
2106 : }
2107 :
2108 164 : return eErr;
2109 : #else
2110 : return OGRERR_FAILURE;
2111 : #endif
2112 : }
2113 :
2114 : //! @endcond
2115 :
2116 : /************************************************************************/
2117 : /* SyncToDisk() */
2118 : /************************************************************************/
2119 :
2120 4767 : OGRErr OGRLayer::SyncToDisk()
2121 :
2122 : {
2123 4767 : return OGRERR_NONE;
2124 : }
2125 :
2126 : /************************************************************************/
2127 : /* OGR_L_SyncToDisk() */
2128 : /************************************************************************/
2129 :
2130 251 : OGRErr OGR_L_SyncToDisk(OGRLayerH hLayer)
2131 :
2132 : {
2133 251 : VALIDATE_POINTER1(hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE);
2134 :
2135 : #ifdef OGRAPISPY_ENABLED
2136 251 : if (bOGRAPISpyEnabled)
2137 2 : OGRAPISpy_L_SyncToDisk(hLayer);
2138 : #endif
2139 :
2140 251 : return OGRLayer::FromHandle(hLayer)->SyncToDisk();
2141 : }
2142 :
2143 : /************************************************************************/
2144 : /* DeleteFeature() */
2145 : /************************************************************************/
2146 :
2147 286 : OGRErr OGRLayer::DeleteFeature(CPL_UNUSED GIntBig nFID)
2148 : {
2149 286 : return OGRERR_UNSUPPORTED_OPERATION;
2150 : }
2151 :
2152 : /************************************************************************/
2153 : /* OGR_L_DeleteFeature() */
2154 : /************************************************************************/
2155 :
2156 3346 : OGRErr OGR_L_DeleteFeature(OGRLayerH hLayer, GIntBig nFID)
2157 :
2158 : {
2159 3346 : VALIDATE_POINTER1(hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE);
2160 :
2161 : #ifdef OGRAPISPY_ENABLED
2162 3346 : if (bOGRAPISpyEnabled)
2163 2 : OGRAPISpy_L_DeleteFeature(hLayer, nFID);
2164 : #endif
2165 :
2166 3346 : return OGRLayer::FromHandle(hLayer)->DeleteFeature(nFID);
2167 : }
2168 :
2169 : /************************************************************************/
2170 : /* GetFeaturesRead() */
2171 : /************************************************************************/
2172 :
2173 : //! @cond Doxygen_Suppress
2174 0 : GIntBig OGRLayer::GetFeaturesRead()
2175 :
2176 : {
2177 0 : return m_nFeaturesRead;
2178 : }
2179 :
2180 : //! @endcond
2181 :
2182 : /************************************************************************/
2183 : /* OGR_L_GetFeaturesRead() */
2184 : /************************************************************************/
2185 :
2186 0 : GIntBig OGR_L_GetFeaturesRead(OGRLayerH hLayer)
2187 :
2188 : {
2189 0 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFeaturesRead", 0);
2190 :
2191 0 : return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
2192 : }
2193 :
2194 : /************************************************************************/
2195 : /* GetFIDColumn */
2196 : /************************************************************************/
2197 :
2198 7393 : const char *OGRLayer::GetFIDColumn()
2199 :
2200 : {
2201 7393 : return "";
2202 : }
2203 :
2204 : /************************************************************************/
2205 : /* OGR_L_GetFIDColumn() */
2206 : /************************************************************************/
2207 :
2208 388 : const char *OGR_L_GetFIDColumn(OGRLayerH hLayer)
2209 :
2210 : {
2211 388 : VALIDATE_POINTER1(hLayer, "OGR_L_GetFIDColumn", nullptr);
2212 :
2213 : #ifdef OGRAPISPY_ENABLED
2214 388 : if (bOGRAPISpyEnabled)
2215 2 : OGRAPISpy_L_GetFIDColumn(hLayer);
2216 : #endif
2217 :
2218 388 : return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
2219 : }
2220 :
2221 : /************************************************************************/
2222 : /* GetGeometryColumn() */
2223 : /************************************************************************/
2224 :
2225 3374 : const char *OGRLayer::GetGeometryColumn()
2226 :
2227 : {
2228 3374 : if (GetLayerDefn()->GetGeomFieldCount() > 0)
2229 3294 : return GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef();
2230 : else
2231 80 : return "";
2232 : }
2233 :
2234 : /************************************************************************/
2235 : /* OGR_L_GetGeometryColumn() */
2236 : /************************************************************************/
2237 :
2238 596 : const char *OGR_L_GetGeometryColumn(OGRLayerH hLayer)
2239 :
2240 : {
2241 596 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryColumn", nullptr);
2242 :
2243 : #ifdef OGRAPISPY_ENABLED
2244 596 : if (bOGRAPISpyEnabled)
2245 2 : OGRAPISpy_L_GetGeometryColumn(hLayer);
2246 : #endif
2247 :
2248 596 : return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
2249 : }
2250 :
2251 : /************************************************************************/
2252 : /* GetStyleTable() */
2253 : /************************************************************************/
2254 :
2255 912 : OGRStyleTable *OGRLayer::GetStyleTable()
2256 : {
2257 912 : return m_poStyleTable;
2258 : }
2259 :
2260 : /************************************************************************/
2261 : /* SetStyleTableDirectly() */
2262 : /************************************************************************/
2263 :
2264 0 : void OGRLayer::SetStyleTableDirectly(OGRStyleTable *poStyleTable)
2265 : {
2266 0 : if (m_poStyleTable)
2267 0 : delete m_poStyleTable;
2268 0 : m_poStyleTable = poStyleTable;
2269 0 : }
2270 :
2271 : /************************************************************************/
2272 : /* SetStyleTable() */
2273 : /************************************************************************/
2274 :
2275 909 : void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
2276 : {
2277 909 : if (m_poStyleTable)
2278 0 : delete m_poStyleTable;
2279 909 : if (poStyleTable)
2280 1 : m_poStyleTable = poStyleTable->Clone();
2281 909 : }
2282 :
2283 : /************************************************************************/
2284 : /* OGR_L_GetStyleTable() */
2285 : /************************************************************************/
2286 :
2287 3 : OGRStyleTableH OGR_L_GetStyleTable(OGRLayerH hLayer)
2288 :
2289 : {
2290 3 : VALIDATE_POINTER1(hLayer, "OGR_L_GetStyleTable", nullptr);
2291 :
2292 : return reinterpret_cast<OGRStyleTableH>(
2293 3 : OGRLayer::FromHandle(hLayer)->GetStyleTable());
2294 : }
2295 :
2296 : /************************************************************************/
2297 : /* OGR_L_SetStyleTableDirectly() */
2298 : /************************************************************************/
2299 :
2300 0 : void OGR_L_SetStyleTableDirectly(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
2301 :
2302 : {
2303 0 : VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTableDirectly");
2304 :
2305 0 : OGRLayer::FromHandle(hLayer)->SetStyleTableDirectly(
2306 0 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
2307 : }
2308 :
2309 : /************************************************************************/
2310 : /* OGR_L_SetStyleTable() */
2311 : /************************************************************************/
2312 :
2313 1 : void OGR_L_SetStyleTable(OGRLayerH hLayer, OGRStyleTableH hStyleTable)
2314 :
2315 : {
2316 1 : VALIDATE_POINTER0(hLayer, "OGR_L_SetStyleTable");
2317 1 : VALIDATE_POINTER0(hStyleTable, "OGR_L_SetStyleTable");
2318 :
2319 1 : OGRLayer::FromHandle(hLayer)->SetStyleTable(
2320 1 : reinterpret_cast<OGRStyleTable *>(hStyleTable));
2321 : }
2322 :
2323 : /************************************************************************/
2324 : /* GetName() */
2325 : /************************************************************************/
2326 :
2327 1126760 : const char *OGRLayer::GetName()
2328 :
2329 : {
2330 1126760 : return GetLayerDefn()->GetName();
2331 : }
2332 :
2333 : /************************************************************************/
2334 : /* OGR_L_GetName() */
2335 : /************************************************************************/
2336 :
2337 1426 : const char *OGR_L_GetName(OGRLayerH hLayer)
2338 :
2339 : {
2340 1426 : VALIDATE_POINTER1(hLayer, "OGR_L_GetName", "");
2341 :
2342 : #ifdef OGRAPISPY_ENABLED
2343 1426 : if (bOGRAPISpyEnabled)
2344 2 : OGRAPISpy_L_GetName(hLayer);
2345 : #endif
2346 :
2347 1426 : return OGRLayer::FromHandle(hLayer)->GetName();
2348 : }
2349 :
2350 : /************************************************************************/
2351 : /* GetGeomType() */
2352 : /************************************************************************/
2353 :
2354 217579 : OGRwkbGeometryType OGRLayer::GetGeomType()
2355 : {
2356 217579 : OGRFeatureDefn *poLayerDefn = GetLayerDefn();
2357 217579 : if (poLayerDefn == nullptr)
2358 : {
2359 0 : CPLDebug("OGR", "GetLayerType() returns NULL !");
2360 0 : return wkbUnknown;
2361 : }
2362 217579 : return poLayerDefn->GetGeomType();
2363 : }
2364 :
2365 : /************************************************************************/
2366 : /* OGR_L_GetGeomType() */
2367 : /************************************************************************/
2368 :
2369 1104 : OGRwkbGeometryType OGR_L_GetGeomType(OGRLayerH hLayer)
2370 :
2371 : {
2372 1104 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeomType", wkbUnknown);
2373 :
2374 : #ifdef OGRAPISPY_ENABLED
2375 1104 : if (bOGRAPISpyEnabled)
2376 2 : OGRAPISpy_L_GetGeomType(hLayer);
2377 : #endif
2378 :
2379 1104 : OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
2380 1104 : if (OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag())
2381 : {
2382 1 : eType = OGR_GT_GetLinear(eType);
2383 : }
2384 1104 : return eType;
2385 : }
2386 :
2387 : /************************************************************************/
2388 : /* SetIgnoredFields() */
2389 : /************************************************************************/
2390 :
2391 8421 : OGRErr OGRLayer::SetIgnoredFields(CSLConstList papszFields)
2392 : {
2393 8421 : OGRFeatureDefn *poDefn = GetLayerDefn();
2394 :
2395 : // first set everything as *not* ignored
2396 63388 : for (int iField = 0; iField < poDefn->GetFieldCount(); iField++)
2397 : {
2398 54967 : poDefn->GetFieldDefn(iField)->SetIgnored(FALSE);
2399 : }
2400 19595 : for (int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++)
2401 : {
2402 11174 : poDefn->GetGeomFieldDefn(iField)->SetIgnored(FALSE);
2403 : }
2404 8421 : poDefn->SetStyleIgnored(FALSE);
2405 :
2406 : // ignore some fields
2407 15992 : for (const char *pszFieldName : cpl::Iterate(papszFields))
2408 : {
2409 : // check special fields
2410 7571 : if (EQUAL(pszFieldName, "OGR_GEOMETRY"))
2411 154 : poDefn->SetGeometryIgnored(TRUE);
2412 7417 : else if (EQUAL(pszFieldName, "OGR_STYLE"))
2413 13 : poDefn->SetStyleIgnored(TRUE);
2414 : else
2415 : {
2416 : // check ordinary fields
2417 7404 : int iField = poDefn->GetFieldIndex(pszFieldName);
2418 7404 : if (iField == -1)
2419 : {
2420 : // check geometry field
2421 1660 : iField = poDefn->GetGeomFieldIndex(pszFieldName);
2422 1660 : if (iField == -1)
2423 : {
2424 0 : return OGRERR_FAILURE;
2425 : }
2426 : else
2427 1660 : poDefn->GetGeomFieldDefn(iField)->SetIgnored(TRUE);
2428 : }
2429 : else
2430 5744 : poDefn->GetFieldDefn(iField)->SetIgnored(TRUE);
2431 : }
2432 : }
2433 :
2434 8421 : return OGRERR_NONE;
2435 : }
2436 :
2437 : /************************************************************************/
2438 : /* OGR_L_SetIgnoredFields() */
2439 : /************************************************************************/
2440 :
2441 265 : OGRErr OGR_L_SetIgnoredFields(OGRLayerH hLayer, const char **papszFields)
2442 :
2443 : {
2444 265 : VALIDATE_POINTER1(hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE);
2445 :
2446 : #ifdef OGRAPISPY_ENABLED
2447 265 : if (bOGRAPISpyEnabled)
2448 2 : OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
2449 : #endif
2450 :
2451 265 : return OGRLayer::FromHandle(hLayer)->SetIgnoredFields(papszFields);
2452 : }
2453 :
2454 : /************************************************************************/
2455 : /* Rename() */
2456 : /************************************************************************/
2457 :
2458 : /** Rename layer.
2459 : *
2460 : * This operation is implemented only by layers that expose the OLCRename
2461 : * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
2462 : *
2463 : * This operation will fail if a layer with the new name already exists.
2464 : *
2465 : * On success, GetDescription() and GetLayerDefn()->GetName() will return
2466 : * pszNewName.
2467 : *
2468 : * Renaming the layer may interrupt current feature iteration.
2469 : *
2470 : * @param pszNewName New layer name. Must not be NULL.
2471 : * @return OGRERR_NONE in case of success
2472 : *
2473 : * @since GDAL 3.5
2474 : */
2475 0 : OGRErr OGRLayer::Rename(CPL_UNUSED const char *pszNewName)
2476 : {
2477 0 : CPLError(CE_Failure, CPLE_NotSupported,
2478 : "Rename() not supported by this layer.");
2479 :
2480 0 : return OGRERR_UNSUPPORTED_OPERATION;
2481 : }
2482 :
2483 : /************************************************************************/
2484 : /* OGR_L_Rename() */
2485 : /************************************************************************/
2486 :
2487 : /** Rename layer.
2488 : *
2489 : * This operation is implemented only by layers that expose the OLCRename
2490 : * capability, and drivers that expose the GDAL_DCAP_RENAME_LAYERS capability
2491 : *
2492 : * This operation will fail if a layer with the new name already exists.
2493 : *
2494 : * On success, GetDescription() and GetLayerDefn()->GetName() will return
2495 : * pszNewName.
2496 : *
2497 : * Renaming the layer may interrupt current feature iteration.
2498 : *
2499 : * @param hLayer Layer to rename.
2500 : * @param pszNewName New layer name. Must not be NULL.
2501 : * @return OGRERR_NONE in case of success
2502 : *
2503 : * @since GDAL 3.5
2504 : */
2505 37 : OGRErr OGR_L_Rename(OGRLayerH hLayer, const char *pszNewName)
2506 :
2507 : {
2508 37 : VALIDATE_POINTER1(hLayer, "OGR_L_Rename", OGRERR_INVALID_HANDLE);
2509 37 : VALIDATE_POINTER1(pszNewName, "OGR_L_Rename", OGRERR_FAILURE);
2510 :
2511 37 : return OGRLayer::FromHandle(hLayer)->Rename(pszNewName);
2512 : }
2513 :
2514 : /************************************************************************/
2515 : /* helper functions for layer overlay methods */
2516 : /************************************************************************/
2517 :
2518 50 : static OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
2519 : {
2520 50 : OGRErr ret = OGRERR_NONE;
2521 50 : OGRGeometry *g = pLayer->GetSpatialFilter();
2522 50 : *ppGeometry = g ? g->clone() : nullptr;
2523 50 : return ret;
2524 : }
2525 :
2526 69 : static OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
2527 : {
2528 69 : OGRErr ret = OGRERR_NONE;
2529 69 : int n = poDefn->GetFieldCount();
2530 69 : if (n > 0)
2531 : {
2532 41 : *map = static_cast<int *>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
2533 41 : if (!(*map))
2534 0 : return OGRERR_NOT_ENOUGH_MEMORY;
2535 115 : for (int i = 0; i < n; i++)
2536 74 : (*map)[i] = -1;
2537 : }
2538 69 : return ret;
2539 : }
2540 :
2541 39 : static OGRErr set_result_schema(OGRLayer *pLayerResult,
2542 : OGRFeatureDefn *poDefnInput,
2543 : OGRFeatureDefn *poDefnMethod, int *mapInput,
2544 : int *mapMethod, bool combined,
2545 : const char *const *papszOptions)
2546 : {
2547 39 : OGRErr ret = OGRERR_NONE;
2548 39 : OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
2549 : const char *pszInputPrefix =
2550 39 : CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
2551 : const char *pszMethodPrefix =
2552 39 : CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
2553 : int bSkipFailures =
2554 39 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
2555 39 : if (poDefnResult->GetFieldCount() > 0)
2556 : {
2557 : // the user has defined the schema of the output layer
2558 4 : if (mapInput)
2559 : {
2560 9 : for (int iField = 0; iField < poDefnInput->GetFieldCount();
2561 : iField++)
2562 : {
2563 : CPLString osName(
2564 5 : poDefnInput->GetFieldDefn(iField)->GetNameRef());
2565 5 : if (pszInputPrefix != nullptr)
2566 0 : osName = pszInputPrefix + osName;
2567 5 : mapInput[iField] = poDefnResult->GetFieldIndex(osName);
2568 : }
2569 : }
2570 4 : if (!mapMethod)
2571 2 : return ret;
2572 : // cppcheck-suppress nullPointer
2573 5 : for (int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++)
2574 : {
2575 : // cppcheck-suppress nullPointer
2576 3 : CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
2577 3 : if (pszMethodPrefix != nullptr)
2578 0 : osName = pszMethodPrefix + osName;
2579 3 : mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
2580 : }
2581 : }
2582 : else
2583 : {
2584 : // use schema from the input layer or from input and method layers
2585 35 : int nFieldsInput = poDefnInput->GetFieldCount();
2586 :
2587 : // If no prefix is specified and we have input+method layers, make
2588 : // sure we will generate unique field names
2589 35 : std::set<std::string> oSetInputFieldNames;
2590 35 : std::set<std::string> oSetMethodFieldNames;
2591 35 : if (poDefnMethod != nullptr && pszInputPrefix == nullptr &&
2592 : pszMethodPrefix == nullptr)
2593 : {
2594 56 : for (int iField = 0; iField < nFieldsInput; iField++)
2595 : {
2596 : oSetInputFieldNames.insert(
2597 28 : poDefnInput->GetFieldDefn(iField)->GetNameRef());
2598 : }
2599 28 : const int nFieldsMethod = poDefnMethod->GetFieldCount();
2600 54 : for (int iField = 0; iField < nFieldsMethod; iField++)
2601 : {
2602 : oSetMethodFieldNames.insert(
2603 26 : poDefnMethod->GetFieldDefn(iField)->GetNameRef());
2604 : }
2605 : }
2606 :
2607 75 : for (int iField = 0; iField < nFieldsInput; iField++)
2608 : {
2609 40 : OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
2610 40 : if (pszInputPrefix != nullptr)
2611 0 : oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix,
2612 : oFieldDefn.GetNameRef()));
2613 66 : else if (!oSetMethodFieldNames.empty() &&
2614 66 : oSetMethodFieldNames.find(oFieldDefn.GetNameRef()) !=
2615 66 : oSetMethodFieldNames.end())
2616 : {
2617 : // Field of same name present in method layer
2618 17 : oFieldDefn.SetName(
2619 : CPLSPrintf("input_%s", oFieldDefn.GetNameRef()));
2620 : }
2621 40 : ret = pLayerResult->CreateField(&oFieldDefn);
2622 40 : if (ret != OGRERR_NONE)
2623 : {
2624 0 : if (!bSkipFailures)
2625 0 : return ret;
2626 : else
2627 : {
2628 0 : CPLErrorReset();
2629 0 : ret = OGRERR_NONE;
2630 : }
2631 : }
2632 40 : if (mapInput)
2633 40 : mapInput[iField] = iField;
2634 : }
2635 35 : if (!combined)
2636 11 : return ret;
2637 24 : if (!mapMethod)
2638 12 : return ret;
2639 12 : if (!poDefnMethod)
2640 0 : return ret;
2641 12 : const int nFieldsMethod = poDefnMethod->GetFieldCount();
2642 34 : for (int iField = 0; iField < nFieldsMethod; iField++)
2643 : {
2644 22 : OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
2645 22 : if (pszMethodPrefix != nullptr)
2646 0 : oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix,
2647 : oFieldDefn.GetNameRef()));
2648 44 : else if (!oSetInputFieldNames.empty() &&
2649 44 : oSetInputFieldNames.find(oFieldDefn.GetNameRef()) !=
2650 44 : oSetInputFieldNames.end())
2651 : {
2652 : // Field of same name present in method layer
2653 15 : oFieldDefn.SetName(
2654 : CPLSPrintf("method_%s", oFieldDefn.GetNameRef()));
2655 : }
2656 22 : ret = pLayerResult->CreateField(&oFieldDefn);
2657 22 : if (ret != OGRERR_NONE)
2658 : {
2659 0 : if (!bSkipFailures)
2660 0 : return ret;
2661 : else
2662 : {
2663 0 : CPLErrorReset();
2664 0 : ret = OGRERR_NONE;
2665 : }
2666 : }
2667 22 : mapMethod[iField] = nFieldsInput + iField;
2668 : }
2669 : }
2670 14 : return ret;
2671 : }
2672 :
2673 91 : static OGRGeometry *set_filter_from(OGRLayer *pLayer,
2674 : OGRGeometry *pGeometryExistingFilter,
2675 : OGRFeature *pFeature)
2676 : {
2677 91 : OGRGeometry *geom = pFeature->GetGeometryRef();
2678 91 : if (!geom)
2679 0 : return nullptr;
2680 91 : if (pGeometryExistingFilter)
2681 : {
2682 0 : if (!geom->Intersects(pGeometryExistingFilter))
2683 0 : return nullptr;
2684 0 : OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
2685 0 : if (intersection)
2686 : {
2687 0 : pLayer->SetSpatialFilter(intersection);
2688 0 : delete intersection;
2689 : }
2690 : else
2691 0 : return nullptr;
2692 : }
2693 : else
2694 : {
2695 91 : pLayer->SetSpatialFilter(geom);
2696 : }
2697 91 : return geom;
2698 : }
2699 :
2700 23 : static OGRGeometry *promote_to_multi(OGRGeometry *poGeom)
2701 : {
2702 23 : OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
2703 23 : if (eType == wkbPoint)
2704 1 : return OGRGeometryFactory::forceToMultiPoint(poGeom);
2705 22 : else if (eType == wkbPolygon)
2706 22 : return OGRGeometryFactory::forceToMultiPolygon(poGeom);
2707 0 : else if (eType == wkbLineString)
2708 0 : return OGRGeometryFactory::forceToMultiLineString(poGeom);
2709 : else
2710 0 : return poGeom;
2711 : }
2712 :
2713 : /************************************************************************/
2714 : /* Intersection() */
2715 : /************************************************************************/
2716 : /**
2717 : * \brief Intersection of two layers.
2718 : *
2719 : * The result layer contains features whose geometries represent areas
2720 : * that are common between features in the input layer and in the
2721 : * method layer. The features in the result layer have attributes from
2722 : * both input and method layers. The schema of the result layer can be
2723 : * set by the user or, if it is empty, is initialized to contain all
2724 : * fields in the input and method layers.
2725 : *
2726 : * \note If the schema of the result is set by user and contains
2727 : * fields that have the same name as a field in input and in method
2728 : * layer, then the attribute in the result feature will get the value
2729 : * from the feature of the method layer.
2730 : *
2731 : * \note For best performance use the minimum amount of features in
2732 : * the method layer and copy it into a memory layer.
2733 : *
2734 : * \note This method relies on GEOS support. Do not use unless the
2735 : * GEOS support is compiled in.
2736 : *
2737 : * The recognized list of options is:
2738 : * <ul>
2739 : * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
2740 : * feature could not be inserted or a GEOS call failed.
2741 : * </li>
2742 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
2743 : * into MultiPolygons, LineStrings to MultiLineStrings or
2744 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
2745 : * </li>
2746 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
2747 : * will be created from the fields of the input layer.
2748 : * </li>
2749 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
2750 : * will be created from the fields of the method layer.
2751 : * </li>
2752 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
2753 : * geometries to pretest intersection of features of method layer
2754 : * with features of this layer.
2755 : * </li>
2756 : * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
2757 : * containment of features of method layer within the features of
2758 : * this layer. This will speed up the method significantly in some
2759 : * cases. Requires that the prepared geometries are in effect.
2760 : * </li>
2761 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
2762 : * result features with lower dimension geometry that would
2763 : * otherwise be added to the result layer. The default is YES, to add
2764 : * features with lower dimension geometry, but only if the result layer
2765 : * has an unknown geometry type.
2766 : * </li>
2767 : * </ul>
2768 : *
2769 : * This method is the same as the C function OGR_L_Intersection().
2770 : *
2771 : * @param pLayerMethod the method layer. Should not be NULL.
2772 : *
2773 : * @param pLayerResult the layer where the features resulting from the
2774 : * operation are inserted. Should not be NULL. See above the note
2775 : * about the schema.
2776 : *
2777 : * @param papszOptions NULL terminated list of options (may be NULL).
2778 : *
2779 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
2780 : * reporting progress or NULL.
2781 : *
2782 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
2783 : *
2784 : * @return an error code if there was an error or the execution was
2785 : * interrupted, OGRERR_NONE otherwise.
2786 : *
2787 : * @note The first geometry field is always used.
2788 : *
2789 : * @since OGR 1.10
2790 : */
2791 :
2792 8 : OGRErr OGRLayer::Intersection(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
2793 : char **papszOptions, GDALProgressFunc pfnProgress,
2794 : void *pProgressArg)
2795 : {
2796 8 : OGRErr ret = OGRERR_NONE;
2797 8 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
2798 8 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
2799 8 : OGRFeatureDefn *poDefnResult = nullptr;
2800 8 : OGRGeometry *pGeometryMethodFilter = nullptr;
2801 8 : int *mapInput = nullptr;
2802 8 : int *mapMethod = nullptr;
2803 8 : OGREnvelope sEnvelopeMethod;
2804 : GBool bEnvelopeSet;
2805 8 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
2806 8 : double progress_counter = 0;
2807 8 : double progress_ticker = 0;
2808 : const bool bSkipFailures =
2809 8 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
2810 8 : const bool bPromoteToMulti = CPLTestBool(
2811 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
2812 8 : const bool bUsePreparedGeometries = CPLTestBool(
2813 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
2814 8 : const bool bPretestContainment = CPLTestBool(
2815 : CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
2816 8 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
2817 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
2818 :
2819 : // check for GEOS
2820 8 : if (!OGRGeometryFactory::haveGEOS())
2821 : {
2822 0 : CPLError(CE_Failure, CPLE_AppDefined,
2823 : "OGRLayer::Intersection() requires GEOS support");
2824 0 : return OGRERR_UNSUPPORTED_OPERATION;
2825 : }
2826 :
2827 : // get resources
2828 8 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
2829 8 : if (ret != OGRERR_NONE)
2830 0 : goto done;
2831 8 : ret = create_field_map(poDefnInput, &mapInput);
2832 8 : if (ret != OGRERR_NONE)
2833 0 : goto done;
2834 8 : ret = create_field_map(poDefnMethod, &mapMethod);
2835 8 : if (ret != OGRERR_NONE)
2836 0 : goto done;
2837 8 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
2838 : mapMethod, true, papszOptions);
2839 8 : if (ret != OGRERR_NONE)
2840 0 : goto done;
2841 8 : poDefnResult = pLayerResult->GetLayerDefn();
2842 8 : bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
2843 8 : if (bKeepLowerDimGeom)
2844 : {
2845 : // require that the result layer is of geom type unknown
2846 6 : if (pLayerResult->GetGeomType() != wkbUnknown)
2847 : {
2848 1 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
2849 : "since the result layer does not allow it.");
2850 1 : bKeepLowerDimGeom = false;
2851 : }
2852 : }
2853 :
2854 22 : for (auto &&x : this)
2855 : {
2856 :
2857 14 : if (pfnProgress)
2858 : {
2859 3 : double p = progress_counter / progress_max;
2860 3 : if (p > progress_ticker)
2861 : {
2862 1 : if (!pfnProgress(p, "", pProgressArg))
2863 : {
2864 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
2865 0 : ret = OGRERR_FAILURE;
2866 0 : goto done;
2867 : }
2868 : }
2869 3 : progress_counter += 1.0;
2870 : }
2871 :
2872 : // is it worth to proceed?
2873 14 : if (bEnvelopeSet)
2874 : {
2875 14 : OGRGeometry *x_geom = x->GetGeometryRef();
2876 14 : if (x_geom)
2877 : {
2878 14 : OGREnvelope x_env;
2879 14 : x_geom->getEnvelope(&x_env);
2880 14 : if (x_env.MaxX < sEnvelopeMethod.MinX ||
2881 14 : x_env.MaxY < sEnvelopeMethod.MinY ||
2882 14 : sEnvelopeMethod.MaxX < x_env.MinX ||
2883 14 : sEnvelopeMethod.MaxY < x_env.MinY)
2884 : {
2885 0 : continue;
2886 : }
2887 : }
2888 : else
2889 : {
2890 0 : continue;
2891 : }
2892 : }
2893 :
2894 : // set up the filter for method layer
2895 14 : CPLErrorReset();
2896 : OGRGeometry *x_geom =
2897 14 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
2898 14 : if (CPLGetLastErrorType() != CE_None)
2899 : {
2900 0 : if (!bSkipFailures)
2901 : {
2902 0 : ret = OGRERR_FAILURE;
2903 0 : goto done;
2904 : }
2905 : else
2906 : {
2907 0 : CPLErrorReset();
2908 0 : ret = OGRERR_NONE;
2909 : }
2910 : }
2911 14 : if (!x_geom)
2912 : {
2913 0 : continue;
2914 : }
2915 :
2916 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
2917 14 : if (bUsePreparedGeometries)
2918 : {
2919 14 : x_prepared_geom.reset(
2920 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
2921 14 : if (!x_prepared_geom)
2922 : {
2923 0 : goto done;
2924 : }
2925 : }
2926 :
2927 30 : for (auto &&y : pLayerMethod)
2928 : {
2929 16 : OGRGeometry *y_geom = y->GetGeometryRef();
2930 16 : if (!y_geom)
2931 4 : continue;
2932 0 : OGRGeometryUniquePtr z_geom;
2933 :
2934 16 : if (x_prepared_geom)
2935 : {
2936 16 : CPLErrorReset();
2937 16 : ret = OGRERR_NONE;
2938 16 : if (bPretestContainment &&
2939 0 : OGRPreparedGeometryContains(x_prepared_geom.get(),
2940 : OGRGeometry::ToHandle(y_geom)))
2941 : {
2942 0 : if (CPLGetLastErrorType() == CE_None)
2943 0 : z_geom.reset(y_geom->clone());
2944 : }
2945 16 : else if (!(OGRPreparedGeometryIntersects(
2946 : x_prepared_geom.get(),
2947 : OGRGeometry::ToHandle(y_geom))))
2948 : {
2949 0 : if (CPLGetLastErrorType() == CE_None)
2950 : {
2951 0 : continue;
2952 : }
2953 : }
2954 16 : if (CPLGetLastErrorType() != CE_None)
2955 : {
2956 0 : if (!bSkipFailures)
2957 : {
2958 0 : ret = OGRERR_FAILURE;
2959 0 : goto done;
2960 : }
2961 : else
2962 : {
2963 0 : CPLErrorReset();
2964 0 : ret = OGRERR_NONE;
2965 0 : continue;
2966 : }
2967 : }
2968 : }
2969 16 : if (!z_geom)
2970 : {
2971 16 : CPLErrorReset();
2972 16 : z_geom.reset(x_geom->Intersection(y_geom));
2973 16 : if (CPLGetLastErrorType() != CE_None || z_geom == nullptr)
2974 : {
2975 0 : if (!bSkipFailures)
2976 : {
2977 0 : ret = OGRERR_FAILURE;
2978 0 : goto done;
2979 : }
2980 : else
2981 : {
2982 0 : CPLErrorReset();
2983 0 : ret = OGRERR_NONE;
2984 0 : continue;
2985 : }
2986 : }
2987 32 : if (z_geom->IsEmpty() ||
2988 16 : (!bKeepLowerDimGeom &&
2989 7 : (x_geom->getDimension() == y_geom->getDimension() &&
2990 7 : z_geom->getDimension() < x_geom->getDimension())))
2991 : {
2992 4 : continue;
2993 : }
2994 : }
2995 12 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
2996 12 : z->SetFieldsFrom(x.get(), mapInput);
2997 12 : z->SetFieldsFrom(y.get(), mapMethod);
2998 12 : if (bPromoteToMulti)
2999 3 : z_geom.reset(promote_to_multi(z_geom.release()));
3000 12 : z->SetGeometryDirectly(z_geom.release());
3001 12 : ret = pLayerResult->CreateFeature(z.get());
3002 :
3003 12 : if (ret != OGRERR_NONE)
3004 : {
3005 0 : if (!bSkipFailures)
3006 : {
3007 0 : goto done;
3008 : }
3009 : else
3010 : {
3011 0 : CPLErrorReset();
3012 0 : ret = OGRERR_NONE;
3013 : }
3014 : }
3015 : }
3016 : }
3017 8 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
3018 : {
3019 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3020 0 : ret = OGRERR_FAILURE;
3021 0 : goto done;
3022 : }
3023 8 : done:
3024 : // release resources
3025 8 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3026 8 : if (pGeometryMethodFilter)
3027 0 : delete pGeometryMethodFilter;
3028 8 : if (mapInput)
3029 4 : VSIFree(mapInput);
3030 8 : if (mapMethod)
3031 4 : VSIFree(mapMethod);
3032 8 : return ret;
3033 : }
3034 :
3035 : /************************************************************************/
3036 : /* OGR_L_Intersection() */
3037 : /************************************************************************/
3038 : /**
3039 : * \brief Intersection of two layers.
3040 : *
3041 : * The result layer contains features whose geometries represent areas
3042 : * that are common between features in the input layer and in the
3043 : * method layer. The features in the result layer have attributes from
3044 : * both input and method layers. The schema of the result layer can be
3045 : * set by the user or, if it is empty, is initialized to contain all
3046 : * fields in the input and method layers.
3047 : *
3048 : * \note If the schema of the result is set by user and contains
3049 : * fields that have the same name as a field in input and in method
3050 : * layer, then the attribute in the result feature will get the value
3051 : * from the feature of the method layer.
3052 : *
3053 : * \note For best performance use the minimum amount of features in
3054 : * the method layer and copy it into a memory layer.
3055 : *
3056 : * \note This method relies on GEOS support. Do not use unless the
3057 : * GEOS support is compiled in.
3058 : *
3059 : * The recognized list of options is :
3060 : * <ul>
3061 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3062 : * feature could not be inserted or a GEOS call failed.
3063 : * </li>
3064 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3065 : * into MultiPolygons, LineStrings to MultiLineStrings or
3066 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
3067 : * </li>
3068 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3069 : * will be created from the fields of the input layer.
3070 : * </li>
3071 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3072 : * will be created from the fields of the method layer.
3073 : * </li>
3074 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3075 : * geometries to pretest intersection of features of method layer
3076 : * with features of this layer.
3077 : * </li>
3078 : * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
3079 : * containment of features of method layer within the features of
3080 : * this layer. This will speed up the method significantly in some
3081 : * cases. Requires that the prepared geometries are in effect.
3082 : * </li>
3083 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3084 : * result features with lower dimension geometry that would
3085 : * otherwise be added to the result layer. The default is YES, to add
3086 : * features with lower dimension geometry, but only if the result layer
3087 : * has an unknown geometry type.
3088 : * </li>
3089 : * </ul>
3090 : *
3091 : * This function is the same as the C++ method OGRLayer::Intersection().
3092 : *
3093 : * @param pLayerInput the input layer. Should not be NULL.
3094 : *
3095 : * @param pLayerMethod the method layer. Should not be NULL.
3096 : *
3097 : * @param pLayerResult the layer where the features resulting from the
3098 : * operation are inserted. Should not be NULL. See above the note
3099 : * about the schema.
3100 : *
3101 : * @param papszOptions NULL terminated list of options (may be NULL).
3102 : *
3103 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3104 : * reporting progress or NULL.
3105 : *
3106 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3107 : *
3108 : * @return an error code if there was an error or the execution was
3109 : * interrupted, OGRERR_NONE otherwise.
3110 : *
3111 : * @note The first geometry field is always used.
3112 : *
3113 : * @since OGR 1.10
3114 : */
3115 :
3116 8 : OGRErr OGR_L_Intersection(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
3117 : OGRLayerH pLayerResult, char **papszOptions,
3118 : GDALProgressFunc pfnProgress, void *pProgressArg)
3119 :
3120 : {
3121 8 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE);
3122 8 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Intersection",
3123 : OGRERR_INVALID_HANDLE);
3124 8 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Intersection",
3125 : OGRERR_INVALID_HANDLE);
3126 :
3127 : return OGRLayer::FromHandle(pLayerInput)
3128 8 : ->Intersection(OGRLayer::FromHandle(pLayerMethod),
3129 : OGRLayer::FromHandle(pLayerResult), papszOptions,
3130 8 : pfnProgress, pProgressArg);
3131 : }
3132 :
3133 : /************************************************************************/
3134 : /* Union() */
3135 : /************************************************************************/
3136 :
3137 : /**
3138 : * \brief Union of two layers.
3139 : *
3140 : * The result layer contains features whose geometries represent areas
3141 : * that are either in the input layer, in the method layer, or in
3142 : * both. The features in the result layer have attributes from both
3143 : * input and method layers. For features which represent areas that
3144 : * are only in the input or in the method layer the respective
3145 : * attributes have undefined values. The schema of the result layer
3146 : * can be set by the user or, if it is empty, is initialized to
3147 : * contain all fields in the input and method layers.
3148 : *
3149 : * \note If the schema of the result is set by user and contains
3150 : * fields that have the same name as a field in input and in method
3151 : * layer, then the attribute in the result feature will get the value
3152 : * from the feature of the method layer (even if it is undefined).
3153 : *
3154 : * \note For best performance use the minimum amount of features in
3155 : * the method layer and copy it into a memory layer.
3156 : *
3157 : * \note This method relies on GEOS support. Do not use unless the
3158 : * GEOS support is compiled in.
3159 : *
3160 : * The recognized list of options is :
3161 : * <ul>
3162 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3163 : * feature could not be inserted or a GEOS call failed.
3164 : * </li>
3165 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3166 : * into MultiPolygons, LineStrings to MultiLineStrings or
3167 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
3168 : * </li>
3169 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3170 : * will be created from the fields of the input layer.
3171 : * </li>
3172 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3173 : * will be created from the fields of the method layer.
3174 : * </li>
3175 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3176 : * geometries to pretest intersection of features of method layer
3177 : * with features of this layer.
3178 : * </li>
3179 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3180 : * result features with lower dimension geometry that would
3181 : * otherwise be added to the result layer. The default is YES, to add
3182 : * features with lower dimension geometry, but only if the result layer
3183 : * has an unknown geometry type.
3184 : * </li>
3185 : * </ul>
3186 : *
3187 : * This method is the same as the C function OGR_L_Union().
3188 : *
3189 : * @param pLayerMethod the method layer. Should not be NULL.
3190 : *
3191 : * @param pLayerResult the layer where the features resulting from the
3192 : * operation are inserted. Should not be NULL. See above the note
3193 : * about the schema.
3194 : *
3195 : * @param papszOptions NULL terminated list of options (may be NULL).
3196 : *
3197 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3198 : * reporting progress or NULL.
3199 : *
3200 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3201 : *
3202 : * @return an error code if there was an error or the execution was
3203 : * interrupted, OGRERR_NONE otherwise.
3204 : *
3205 : * @note The first geometry field is always used.
3206 : *
3207 : * @since OGR 1.10
3208 : */
3209 :
3210 7 : OGRErr OGRLayer::Union(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
3211 : char **papszOptions, GDALProgressFunc pfnProgress,
3212 : void *pProgressArg)
3213 : {
3214 7 : OGRErr ret = OGRERR_NONE;
3215 7 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
3216 7 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3217 7 : OGRFeatureDefn *poDefnResult = nullptr;
3218 7 : OGRGeometry *pGeometryMethodFilter = nullptr;
3219 7 : OGRGeometry *pGeometryInputFilter = nullptr;
3220 7 : int *mapInput = nullptr;
3221 7 : int *mapMethod = nullptr;
3222 : double progress_max =
3223 7 : static_cast<double>(GetFeatureCount(FALSE)) +
3224 7 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
3225 7 : double progress_counter = 0;
3226 7 : double progress_ticker = 0;
3227 : const bool bSkipFailures =
3228 7 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3229 7 : const bool bPromoteToMulti = CPLTestBool(
3230 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3231 7 : const bool bUsePreparedGeometries = CPLTestBool(
3232 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
3233 7 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
3234 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
3235 :
3236 : // check for GEOS
3237 7 : if (!OGRGeometryFactory::haveGEOS())
3238 : {
3239 0 : CPLError(CE_Failure, CPLE_AppDefined,
3240 : "OGRLayer::Union() requires GEOS support");
3241 0 : return OGRERR_UNSUPPORTED_OPERATION;
3242 : }
3243 :
3244 : // get resources
3245 7 : ret = clone_spatial_filter(this, &pGeometryInputFilter);
3246 7 : if (ret != OGRERR_NONE)
3247 0 : goto done;
3248 7 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3249 7 : if (ret != OGRERR_NONE)
3250 0 : goto done;
3251 7 : ret = create_field_map(poDefnInput, &mapInput);
3252 7 : if (ret != OGRERR_NONE)
3253 0 : goto done;
3254 7 : ret = create_field_map(poDefnMethod, &mapMethod);
3255 7 : if (ret != OGRERR_NONE)
3256 0 : goto done;
3257 7 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
3258 : mapMethod, true, papszOptions);
3259 7 : if (ret != OGRERR_NONE)
3260 0 : goto done;
3261 7 : poDefnResult = pLayerResult->GetLayerDefn();
3262 7 : if (bKeepLowerDimGeom)
3263 : {
3264 : // require that the result layer is of geom type unknown
3265 5 : if (pLayerResult->GetGeomType() != wkbUnknown)
3266 : {
3267 0 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
3268 : "since the result layer does not allow it.");
3269 0 : bKeepLowerDimGeom = FALSE;
3270 : }
3271 : }
3272 :
3273 : // add features based on input layer
3274 20 : for (auto &&x : this)
3275 : {
3276 :
3277 13 : if (pfnProgress)
3278 : {
3279 2 : double p = progress_counter / progress_max;
3280 2 : if (p > progress_ticker)
3281 : {
3282 1 : if (!pfnProgress(p, "", pProgressArg))
3283 : {
3284 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3285 0 : ret = OGRERR_FAILURE;
3286 0 : goto done;
3287 : }
3288 : }
3289 2 : progress_counter += 1.0;
3290 : }
3291 :
3292 : // set up the filter on method layer
3293 13 : CPLErrorReset();
3294 : OGRGeometry *x_geom =
3295 13 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3296 13 : if (CPLGetLastErrorType() != CE_None)
3297 : {
3298 0 : if (!bSkipFailures)
3299 : {
3300 0 : ret = OGRERR_FAILURE;
3301 0 : goto done;
3302 : }
3303 : else
3304 : {
3305 0 : CPLErrorReset();
3306 0 : ret = OGRERR_NONE;
3307 : }
3308 : }
3309 13 : if (!x_geom)
3310 : {
3311 0 : continue;
3312 : }
3313 :
3314 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
3315 13 : if (bUsePreparedGeometries)
3316 : {
3317 13 : x_prepared_geom.reset(
3318 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
3319 13 : if (!x_prepared_geom)
3320 : {
3321 0 : goto done;
3322 : }
3323 : }
3324 :
3325 : OGRGeometryUniquePtr x_geom_diff(
3326 : x_geom
3327 13 : ->clone()); // this will be the geometry of the result feature
3328 28 : for (auto &&y : pLayerMethod)
3329 : {
3330 15 : OGRGeometry *y_geom = y->GetGeometryRef();
3331 15 : if (!y_geom)
3332 : {
3333 0 : continue;
3334 : }
3335 :
3336 15 : CPLErrorReset();
3337 30 : if (x_prepared_geom &&
3338 15 : !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
3339 15 : OGRGeometry::ToHandle(y_geom))))
3340 : {
3341 0 : if (CPLGetLastErrorType() == CE_None)
3342 : {
3343 0 : continue;
3344 : }
3345 : }
3346 15 : if (CPLGetLastErrorType() != CE_None)
3347 : {
3348 0 : if (!bSkipFailures)
3349 : {
3350 0 : ret = OGRERR_FAILURE;
3351 0 : goto done;
3352 : }
3353 : else
3354 : {
3355 0 : CPLErrorReset();
3356 0 : ret = OGRERR_NONE;
3357 : }
3358 : }
3359 :
3360 15 : CPLErrorReset();
3361 15 : OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
3362 15 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
3363 : {
3364 0 : if (!bSkipFailures)
3365 : {
3366 0 : ret = OGRERR_FAILURE;
3367 0 : goto done;
3368 : }
3369 : else
3370 : {
3371 0 : CPLErrorReset();
3372 0 : ret = OGRERR_NONE;
3373 0 : continue;
3374 : }
3375 : }
3376 30 : if (poIntersection->IsEmpty() ||
3377 15 : (!bKeepLowerDimGeom &&
3378 6 : (x_geom->getDimension() == y_geom->getDimension() &&
3379 6 : poIntersection->getDimension() < x_geom->getDimension())))
3380 : {
3381 : // ok
3382 : }
3383 : else
3384 : {
3385 11 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3386 11 : z->SetFieldsFrom(x.get(), mapInput);
3387 11 : z->SetFieldsFrom(y.get(), mapMethod);
3388 11 : if (bPromoteToMulti)
3389 2 : poIntersection.reset(
3390 : promote_to_multi(poIntersection.release()));
3391 11 : z->SetGeometryDirectly(poIntersection.release());
3392 :
3393 11 : if (x_geom_diff)
3394 : {
3395 11 : CPLErrorReset();
3396 : OGRGeometryUniquePtr x_geom_diff_new(
3397 11 : x_geom_diff->Difference(y_geom));
3398 22 : if (CPLGetLastErrorType() != CE_None ||
3399 11 : x_geom_diff_new == nullptr)
3400 : {
3401 0 : if (!bSkipFailures)
3402 : {
3403 0 : ret = OGRERR_FAILURE;
3404 0 : goto done;
3405 : }
3406 : else
3407 : {
3408 0 : CPLErrorReset();
3409 : }
3410 : }
3411 : else
3412 : {
3413 11 : x_geom_diff.swap(x_geom_diff_new);
3414 : }
3415 : }
3416 :
3417 11 : ret = pLayerResult->CreateFeature(z.get());
3418 11 : if (ret != OGRERR_NONE)
3419 : {
3420 0 : if (!bSkipFailures)
3421 : {
3422 0 : goto done;
3423 : }
3424 : else
3425 : {
3426 0 : CPLErrorReset();
3427 0 : ret = OGRERR_NONE;
3428 : }
3429 : }
3430 : }
3431 : }
3432 13 : x_prepared_geom.reset();
3433 :
3434 13 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
3435 : {
3436 : // ok
3437 : }
3438 : else
3439 : {
3440 11 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3441 11 : z->SetFieldsFrom(x.get(), mapInput);
3442 11 : if (bPromoteToMulti)
3443 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
3444 11 : z->SetGeometryDirectly(x_geom_diff.release());
3445 11 : ret = pLayerResult->CreateFeature(z.get());
3446 11 : if (ret != OGRERR_NONE)
3447 : {
3448 0 : if (!bSkipFailures)
3449 : {
3450 0 : goto done;
3451 : }
3452 : else
3453 : {
3454 0 : CPLErrorReset();
3455 0 : ret = OGRERR_NONE;
3456 : }
3457 : }
3458 : }
3459 : }
3460 :
3461 : // restore filter on method layer and add features based on it
3462 7 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3463 17 : for (auto &&x : pLayerMethod)
3464 : {
3465 :
3466 10 : if (pfnProgress)
3467 : {
3468 1 : double p = progress_counter / progress_max;
3469 1 : if (p > progress_ticker)
3470 : {
3471 1 : if (!pfnProgress(p, "", pProgressArg))
3472 : {
3473 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3474 0 : ret = OGRERR_FAILURE;
3475 0 : goto done;
3476 : }
3477 : }
3478 1 : progress_counter += 1.0;
3479 : }
3480 :
3481 : // set up the filter on input layer
3482 10 : CPLErrorReset();
3483 : OGRGeometry *x_geom =
3484 10 : set_filter_from(this, pGeometryInputFilter, x.get());
3485 10 : if (CPLGetLastErrorType() != CE_None)
3486 : {
3487 0 : if (!bSkipFailures)
3488 : {
3489 0 : ret = OGRERR_FAILURE;
3490 0 : goto done;
3491 : }
3492 : else
3493 : {
3494 0 : CPLErrorReset();
3495 0 : ret = OGRERR_NONE;
3496 : }
3497 : }
3498 10 : if (!x_geom)
3499 : {
3500 0 : continue;
3501 : }
3502 :
3503 : OGRGeometryUniquePtr x_geom_diff(
3504 : x_geom
3505 10 : ->clone()); // this will be the geometry of the result feature
3506 25 : for (auto &&y : this)
3507 : {
3508 15 : OGRGeometry *y_geom = y->GetGeometryRef();
3509 15 : if (!y_geom)
3510 : {
3511 0 : continue;
3512 : }
3513 :
3514 15 : if (x_geom_diff)
3515 : {
3516 15 : CPLErrorReset();
3517 : OGRGeometryUniquePtr x_geom_diff_new(
3518 15 : x_geom_diff->Difference(y_geom));
3519 30 : if (CPLGetLastErrorType() != CE_None ||
3520 15 : x_geom_diff_new == nullptr)
3521 : {
3522 0 : if (!bSkipFailures)
3523 : {
3524 0 : ret = OGRERR_FAILURE;
3525 0 : goto done;
3526 : }
3527 : else
3528 : {
3529 0 : CPLErrorReset();
3530 0 : ret = OGRERR_NONE;
3531 : }
3532 : }
3533 : else
3534 : {
3535 15 : x_geom_diff.swap(x_geom_diff_new);
3536 : }
3537 : }
3538 : }
3539 :
3540 10 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
3541 : {
3542 : // ok
3543 : }
3544 : else
3545 : {
3546 7 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3547 7 : z->SetFieldsFrom(x.get(), mapMethod);
3548 7 : if (bPromoteToMulti)
3549 1 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
3550 7 : z->SetGeometryDirectly(x_geom_diff.release());
3551 7 : ret = pLayerResult->CreateFeature(z.get());
3552 7 : if (ret != OGRERR_NONE)
3553 : {
3554 0 : if (!bSkipFailures)
3555 : {
3556 0 : goto done;
3557 : }
3558 : else
3559 : {
3560 0 : CPLErrorReset();
3561 0 : ret = OGRERR_NONE;
3562 : }
3563 : }
3564 : }
3565 : }
3566 7 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
3567 : {
3568 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3569 0 : ret = OGRERR_FAILURE;
3570 0 : goto done;
3571 : }
3572 7 : done:
3573 : // release resources
3574 7 : SetSpatialFilter(pGeometryInputFilter);
3575 7 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3576 7 : if (pGeometryMethodFilter)
3577 0 : delete pGeometryMethodFilter;
3578 7 : if (pGeometryInputFilter)
3579 0 : delete pGeometryInputFilter;
3580 7 : if (mapInput)
3581 4 : VSIFree(mapInput);
3582 7 : if (mapMethod)
3583 3 : VSIFree(mapMethod);
3584 7 : return ret;
3585 : }
3586 :
3587 : /************************************************************************/
3588 : /* OGR_L_Union() */
3589 : /************************************************************************/
3590 :
3591 : /**
3592 : * \brief Union of two layers.
3593 : *
3594 : * The result layer contains features whose geometries represent areas
3595 : * that are in either in the input layer, in the method layer, or in
3596 : * both. The features in the result layer have attributes from both
3597 : * input and method layers. For features which represent areas that
3598 : * are only in the input or in the method layer the respective
3599 : * attributes have undefined values. The schema of the result layer
3600 : * can be set by the user or, if it is empty, is initialized to
3601 : * contain all fields in the input and method layers.
3602 : *
3603 : * \note If the schema of the result is set by user and contains
3604 : * fields that have the same name as a field in input and in method
3605 : * layer, then the attribute in the result feature will get the value
3606 : * from the feature of the method layer (even if it is undefined).
3607 : *
3608 : * \note For best performance use the minimum amount of features in
3609 : * the method layer and copy it into a memory layer.
3610 : *
3611 : * \note This method relies on GEOS support. Do not use unless the
3612 : * GEOS support is compiled in.
3613 : *
3614 : * The recognized list of options is :
3615 : * <ul>
3616 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3617 : * feature could not be inserted or a GEOS call failed.
3618 : * </li>
3619 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
3620 : * into MultiPolygons, LineStrings to MultiLineStrings or
3621 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
3622 : * </li>
3623 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3624 : * will be created from the fields of the input layer.
3625 : * </li>
3626 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3627 : * will be created from the fields of the method layer.
3628 : * </li>
3629 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3630 : * geometries to pretest intersection of features of method layer
3631 : * with features of this layer.
3632 : * </li>
3633 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3634 : * result features with lower dimension geometry that would
3635 : * otherwise be added to the result layer. The default is YES, to add
3636 : * features with lower dimension geometry, but only if the result layer
3637 : * has an unknown geometry type.
3638 : * </li>
3639 : * </ul>
3640 : *
3641 : * This function is the same as the C++ method OGRLayer::Union().
3642 : *
3643 : * @param pLayerInput the input layer. Should not be NULL.
3644 : *
3645 : * @param pLayerMethod the method layer. Should not be NULL.
3646 : *
3647 : * @param pLayerResult the layer where the features resulting from the
3648 : * operation are inserted. Should not be NULL. See above the note
3649 : * about the schema.
3650 : *
3651 : * @param papszOptions NULL terminated list of options (may be NULL).
3652 : *
3653 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3654 : * reporting progress or NULL.
3655 : *
3656 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3657 : *
3658 : * @return an error code if there was an error or the execution was
3659 : * interrupted, OGRERR_NONE otherwise.
3660 : *
3661 : * @note The first geometry field is always used.
3662 : *
3663 : * @since OGR 1.10
3664 : */
3665 :
3666 7 : OGRErr OGR_L_Union(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
3667 : OGRLayerH pLayerResult, char **papszOptions,
3668 : GDALProgressFunc pfnProgress, void *pProgressArg)
3669 :
3670 : {
3671 7 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE);
3672 7 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE);
3673 7 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE);
3674 :
3675 : return OGRLayer::FromHandle(pLayerInput)
3676 7 : ->Union(OGRLayer::FromHandle(pLayerMethod),
3677 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
3678 7 : pProgressArg);
3679 : }
3680 :
3681 : /************************************************************************/
3682 : /* SymDifference() */
3683 : /************************************************************************/
3684 :
3685 : /**
3686 : * \brief Symmetrical difference of two layers.
3687 : *
3688 : * The result layer contains features whose geometries represent areas
3689 : * that are in either in the input layer or in the method layer but
3690 : * not in both. The features in the result layer have attributes from
3691 : * both input and method layers. For features which represent areas
3692 : * that are only in the input or in the method layer the respective
3693 : * attributes have undefined values. The schema of the result layer
3694 : * can be set by the user or, if it is empty, is initialized to
3695 : * contain all fields in the input and method layers.
3696 : *
3697 : * \note If the schema of the result is set by user and contains
3698 : * fields that have the same name as a field in input and in method
3699 : * layer, then the attribute in the result feature will get the value
3700 : * from the feature of the method layer (even if it is undefined).
3701 : *
3702 : * \note For best performance use the minimum amount of features in
3703 : * the method layer and copy it into a memory layer.
3704 : *
3705 : * \note This method relies on GEOS support. Do not use unless the
3706 : * GEOS support is compiled in.
3707 : *
3708 : * The recognized list of options is :
3709 : * <ul>
3710 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3711 : * feature could not be inserted or a GEOS call failed.
3712 : * </li>
3713 : * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
3714 : * into MultiPolygons, or LineStrings to MultiLineStrings.
3715 : * </li>
3716 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3717 : * will be created from the fields of the input layer.
3718 : * </li>
3719 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3720 : * will be created from the fields of the method layer.
3721 : * </li>
3722 : * </ul>
3723 : *
3724 : * This method is the same as the C function OGR_L_SymDifference().
3725 : *
3726 : * @param pLayerMethod the method layer. Should not be NULL.
3727 : *
3728 : * @param pLayerResult the layer where the features resulting from the
3729 : * operation are inserted. Should not be NULL. See above the note
3730 : * about the schema.
3731 : *
3732 : * @param papszOptions NULL terminated list of options (may be NULL).
3733 : *
3734 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
3735 : * reporting progress or NULL.
3736 : *
3737 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3738 : *
3739 : * @return an error code if there was an error or the execution was
3740 : * interrupted, OGRERR_NONE otherwise.
3741 : *
3742 : * @note The first geometry field is always used.
3743 : *
3744 : * @since OGR 1.10
3745 : */
3746 :
3747 4 : OGRErr OGRLayer::SymDifference(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
3748 : char **papszOptions,
3749 : GDALProgressFunc pfnProgress, void *pProgressArg)
3750 : {
3751 4 : OGRErr ret = OGRERR_NONE;
3752 4 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
3753 4 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3754 4 : OGRFeatureDefn *poDefnResult = nullptr;
3755 4 : OGRGeometry *pGeometryMethodFilter = nullptr;
3756 4 : OGRGeometry *pGeometryInputFilter = nullptr;
3757 4 : int *mapInput = nullptr;
3758 4 : int *mapMethod = nullptr;
3759 : double progress_max =
3760 4 : static_cast<double>(GetFeatureCount(FALSE)) +
3761 4 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
3762 4 : double progress_counter = 0;
3763 4 : double progress_ticker = 0;
3764 : const bool bSkipFailures =
3765 4 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3766 4 : const bool bPromoteToMulti = CPLTestBool(
3767 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3768 :
3769 : // check for GEOS
3770 4 : if (!OGRGeometryFactory::haveGEOS())
3771 : {
3772 0 : CPLError(CE_Failure, CPLE_AppDefined,
3773 : "OGRLayer::SymDifference() requires GEOS support");
3774 0 : return OGRERR_UNSUPPORTED_OPERATION;
3775 : }
3776 :
3777 : // get resources
3778 4 : ret = clone_spatial_filter(this, &pGeometryInputFilter);
3779 4 : if (ret != OGRERR_NONE)
3780 0 : goto done;
3781 4 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3782 4 : if (ret != OGRERR_NONE)
3783 0 : goto done;
3784 4 : ret = create_field_map(poDefnInput, &mapInput);
3785 4 : if (ret != OGRERR_NONE)
3786 0 : goto done;
3787 4 : ret = create_field_map(poDefnMethod, &mapMethod);
3788 4 : if (ret != OGRERR_NONE)
3789 0 : goto done;
3790 4 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
3791 : mapMethod, true, papszOptions);
3792 4 : if (ret != OGRERR_NONE)
3793 0 : goto done;
3794 4 : poDefnResult = pLayerResult->GetLayerDefn();
3795 :
3796 : // add features based on input layer
3797 12 : for (auto &&x : this)
3798 : {
3799 :
3800 8 : if (pfnProgress)
3801 : {
3802 2 : double p = progress_counter / progress_max;
3803 2 : if (p > progress_ticker)
3804 : {
3805 1 : if (!pfnProgress(p, "", pProgressArg))
3806 : {
3807 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3808 0 : ret = OGRERR_FAILURE;
3809 0 : goto done;
3810 : }
3811 : }
3812 2 : progress_counter += 1.0;
3813 : }
3814 :
3815 : // set up the filter on method layer
3816 8 : CPLErrorReset();
3817 : OGRGeometry *x_geom =
3818 8 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3819 8 : if (CPLGetLastErrorType() != CE_None)
3820 : {
3821 0 : if (!bSkipFailures)
3822 : {
3823 0 : ret = OGRERR_FAILURE;
3824 0 : goto done;
3825 : }
3826 : else
3827 : {
3828 0 : CPLErrorReset();
3829 0 : ret = OGRERR_NONE;
3830 : }
3831 : }
3832 8 : if (!x_geom)
3833 : {
3834 0 : continue;
3835 : }
3836 :
3837 : OGRGeometryUniquePtr geom(
3838 : x_geom
3839 8 : ->clone()); // this will be the geometry of the result feature
3840 15 : for (auto &&y : pLayerMethod)
3841 : {
3842 9 : OGRGeometry *y_geom = y->GetGeometryRef();
3843 9 : if (!y_geom)
3844 : {
3845 0 : continue;
3846 : }
3847 9 : if (geom)
3848 : {
3849 9 : CPLErrorReset();
3850 9 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
3851 9 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
3852 : {
3853 0 : if (!bSkipFailures)
3854 : {
3855 0 : ret = OGRERR_FAILURE;
3856 0 : goto done;
3857 : }
3858 : else
3859 : {
3860 0 : CPLErrorReset();
3861 0 : ret = OGRERR_NONE;
3862 : }
3863 : }
3864 : else
3865 : {
3866 9 : geom.swap(geom_new);
3867 : }
3868 : }
3869 9 : if (geom && geom->IsEmpty())
3870 2 : break;
3871 : }
3872 :
3873 8 : if (geom && !geom->IsEmpty())
3874 : {
3875 6 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3876 6 : z->SetFieldsFrom(x.get(), mapInput);
3877 6 : if (bPromoteToMulti)
3878 2 : geom.reset(promote_to_multi(geom.release()));
3879 6 : z->SetGeometryDirectly(geom.release());
3880 6 : ret = pLayerResult->CreateFeature(z.get());
3881 6 : if (ret != OGRERR_NONE)
3882 : {
3883 0 : if (!bSkipFailures)
3884 : {
3885 0 : goto done;
3886 : }
3887 : else
3888 : {
3889 0 : CPLErrorReset();
3890 0 : ret = OGRERR_NONE;
3891 : }
3892 : }
3893 : }
3894 : }
3895 :
3896 : // restore filter on method layer and add features based on it
3897 4 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3898 10 : for (auto &&x : pLayerMethod)
3899 : {
3900 :
3901 6 : if (pfnProgress)
3902 : {
3903 2 : double p = progress_counter / progress_max;
3904 2 : if (p > progress_ticker)
3905 : {
3906 2 : if (!pfnProgress(p, "", pProgressArg))
3907 : {
3908 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3909 0 : ret = OGRERR_FAILURE;
3910 0 : goto done;
3911 : }
3912 : }
3913 2 : progress_counter += 1.0;
3914 : }
3915 :
3916 : // set up the filter on input layer
3917 6 : CPLErrorReset();
3918 : OGRGeometry *x_geom =
3919 6 : set_filter_from(this, pGeometryInputFilter, x.get());
3920 6 : if (CPLGetLastErrorType() != CE_None)
3921 : {
3922 0 : if (!bSkipFailures)
3923 : {
3924 0 : ret = OGRERR_FAILURE;
3925 0 : goto done;
3926 : }
3927 : else
3928 : {
3929 0 : CPLErrorReset();
3930 0 : ret = OGRERR_NONE;
3931 : }
3932 : }
3933 6 : if (!x_geom)
3934 : {
3935 0 : continue;
3936 : }
3937 :
3938 : OGRGeometryUniquePtr geom(
3939 : x_geom
3940 6 : ->clone()); // this will be the geometry of the result feature
3941 13 : for (auto &&y : this)
3942 : {
3943 9 : OGRGeometry *y_geom = y->GetGeometryRef();
3944 9 : if (!y_geom)
3945 0 : continue;
3946 9 : if (geom)
3947 : {
3948 9 : CPLErrorReset();
3949 9 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
3950 9 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
3951 : {
3952 0 : if (!bSkipFailures)
3953 : {
3954 0 : ret = OGRERR_FAILURE;
3955 0 : goto done;
3956 : }
3957 : else
3958 : {
3959 0 : CPLErrorReset();
3960 0 : ret = OGRERR_NONE;
3961 : }
3962 : }
3963 : else
3964 : {
3965 9 : geom.swap(geom_new);
3966 : }
3967 : }
3968 9 : if (geom == nullptr || geom->IsEmpty())
3969 2 : break;
3970 : }
3971 :
3972 6 : if (geom && !geom->IsEmpty())
3973 : {
3974 4 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3975 4 : z->SetFieldsFrom(x.get(), mapMethod);
3976 4 : if (bPromoteToMulti)
3977 1 : geom.reset(promote_to_multi(geom.release()));
3978 4 : z->SetGeometryDirectly(geom.release());
3979 4 : ret = pLayerResult->CreateFeature(z.get());
3980 4 : if (ret != OGRERR_NONE)
3981 : {
3982 0 : if (!bSkipFailures)
3983 : {
3984 0 : goto done;
3985 : }
3986 : else
3987 : {
3988 0 : CPLErrorReset();
3989 0 : ret = OGRERR_NONE;
3990 : }
3991 : }
3992 : }
3993 : }
3994 4 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
3995 : {
3996 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3997 0 : ret = OGRERR_FAILURE;
3998 0 : goto done;
3999 : }
4000 4 : done:
4001 : // release resources
4002 4 : SetSpatialFilter(pGeometryInputFilter);
4003 4 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4004 4 : if (pGeometryMethodFilter)
4005 0 : delete pGeometryMethodFilter;
4006 4 : if (pGeometryInputFilter)
4007 0 : delete pGeometryInputFilter;
4008 4 : if (mapInput)
4009 3 : VSIFree(mapInput);
4010 4 : if (mapMethod)
4011 3 : VSIFree(mapMethod);
4012 4 : return ret;
4013 : }
4014 :
4015 : /************************************************************************/
4016 : /* OGR_L_SymDifference() */
4017 : /************************************************************************/
4018 :
4019 : /**
4020 : * \brief Symmetrical difference of two layers.
4021 : *
4022 : * The result layer contains features whose geometries represent areas
4023 : * that are in either in the input layer or in the method layer but
4024 : * not in both. The features in the result layer have attributes from
4025 : * both input and method layers. For features which represent areas
4026 : * that are only in the input or in the method layer the respective
4027 : * attributes have undefined values. The schema of the result layer
4028 : * can be set by the user or, if it is empty, is initialized to
4029 : * contain all fields in the input and method layers.
4030 : *
4031 : * \note If the schema of the result is set by user and contains
4032 : * fields that have the same name as a field in input and in method
4033 : * layer, then the attribute in the result feature will get the value
4034 : * from the feature of the method layer (even if it is undefined).
4035 : *
4036 : * \note For best performance use the minimum amount of features in
4037 : * the method layer and copy it into a memory layer.
4038 : *
4039 : * \note This method relies on GEOS support. Do not use unless the
4040 : * GEOS support is compiled in.
4041 : *
4042 : * The recognized list of options is :
4043 : * <ul>
4044 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4045 : * feature could not be inserted or a GEOS call failed.
4046 : * </li>
4047 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4048 : * into MultiPolygons, LineStrings to MultiLineStrings or
4049 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4050 : * </li>
4051 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4052 : * will be created from the fields of the input layer.
4053 : * </li>
4054 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4055 : * will be created from the fields of the method layer.
4056 : * </li>
4057 : * </ul>
4058 : *
4059 : * This function is the same as the C++ method OGRLayer::SymDifference().
4060 : *
4061 : * @param pLayerInput the input layer. Should not be NULL.
4062 : *
4063 : * @param pLayerMethod the method layer. Should not be NULL.
4064 : *
4065 : * @param pLayerResult the layer where the features resulting from the
4066 : * operation are inserted. Should not be NULL. See above the note
4067 : * about the schema.
4068 : *
4069 : * @param papszOptions NULL terminated list of options (may be NULL).
4070 : *
4071 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4072 : * reporting progress or NULL.
4073 : *
4074 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4075 : *
4076 : * @return an error code if there was an error or the execution was
4077 : * interrupted, OGRERR_NONE otherwise.
4078 : *
4079 : * @note The first geometry field is always used.
4080 : *
4081 : * @since OGR 1.10
4082 : */
4083 :
4084 4 : OGRErr OGR_L_SymDifference(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
4085 : OGRLayerH pLayerResult, char **papszOptions,
4086 : GDALProgressFunc pfnProgress, void *pProgressArg)
4087 :
4088 : {
4089 4 : VALIDATE_POINTER1(pLayerInput, "OGR_L_SymDifference",
4090 : OGRERR_INVALID_HANDLE);
4091 4 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_SymDifference",
4092 : OGRERR_INVALID_HANDLE);
4093 4 : VALIDATE_POINTER1(pLayerResult, "OGR_L_SymDifference",
4094 : OGRERR_INVALID_HANDLE);
4095 :
4096 : return OGRLayer::FromHandle(pLayerInput)
4097 4 : ->SymDifference(OGRLayer::FromHandle(pLayerMethod),
4098 : OGRLayer::FromHandle(pLayerResult), papszOptions,
4099 4 : pfnProgress, pProgressArg);
4100 : }
4101 :
4102 : /************************************************************************/
4103 : /* Identity() */
4104 : /************************************************************************/
4105 :
4106 : /**
4107 : * \brief Identify the features of this layer with the ones from the
4108 : * identity layer.
4109 : *
4110 : * The result layer contains features whose geometries represent areas
4111 : * that are in the input layer. The features in the result layer have
4112 : * attributes from both input and method layers. The schema of the
4113 : * result layer can be set by the user or, if it is empty, is
4114 : * initialized to contain all fields in input and method layers.
4115 : *
4116 : * \note If the schema of the result is set by user and contains
4117 : * fields that have the same name as a field in input and in method
4118 : * layer, then the attribute in the result feature will get the value
4119 : * from the feature of the method layer (even if it is undefined).
4120 : *
4121 : * \note For best performance use the minimum amount of features in
4122 : * the method layer and copy it into a memory layer.
4123 : *
4124 : * \note This method relies on GEOS support. Do not use unless the
4125 : * GEOS support is compiled in.
4126 : *
4127 : * The recognized list of options is :
4128 : * <ul>
4129 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4130 : * feature could not be inserted or a GEOS call failed.
4131 : * </li>
4132 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4133 : * into MultiPolygons, LineStrings to MultiLineStrings or
4134 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4135 : * </li>
4136 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4137 : * will be created from the fields of the input layer.
4138 : * </li>
4139 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4140 : * will be created from the fields of the method layer.
4141 : * </li>
4142 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
4143 : * geometries to pretest intersection of features of method layer
4144 : * with features of this layer.
4145 : * </li>
4146 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
4147 : * result features with lower dimension geometry that would
4148 : * otherwise be added to the result layer. The default is YES, to add
4149 : * features with lower dimension geometry, but only if the result layer
4150 : * has an unknown geometry type.
4151 : * </li>
4152 : * </ul>
4153 : *
4154 : * This method is the same as the C function OGR_L_Identity().
4155 : *
4156 : * @param pLayerMethod the method layer. Should not be NULL.
4157 : *
4158 : * @param pLayerResult the layer where the features resulting from the
4159 : * operation are inserted. Should not be NULL. See above the note
4160 : * about the schema.
4161 : *
4162 : * @param papszOptions NULL terminated list of options (may be NULL).
4163 : *
4164 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4165 : * reporting progress or NULL.
4166 : *
4167 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4168 : *
4169 : * @return an error code if there was an error or the execution was
4170 : * interrupted, OGRERR_NONE otherwise.
4171 : *
4172 : * @note The first geometry field is always used.
4173 : *
4174 : * @since OGR 1.10
4175 : */
4176 :
4177 6 : OGRErr OGRLayer::Identity(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
4178 : char **papszOptions, GDALProgressFunc pfnProgress,
4179 : void *pProgressArg)
4180 : {
4181 6 : OGRErr ret = OGRERR_NONE;
4182 6 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
4183 6 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
4184 6 : OGRFeatureDefn *poDefnResult = nullptr;
4185 6 : OGRGeometry *pGeometryMethodFilter = nullptr;
4186 6 : int *mapInput = nullptr;
4187 6 : int *mapMethod = nullptr;
4188 6 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
4189 6 : double progress_counter = 0;
4190 6 : double progress_ticker = 0;
4191 : const bool bSkipFailures =
4192 6 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4193 6 : const bool bPromoteToMulti = CPLTestBool(
4194 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4195 6 : const bool bUsePreparedGeometries = CPLTestBool(
4196 : CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
4197 6 : bool bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(
4198 : papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
4199 :
4200 : // check for GEOS
4201 6 : if (!OGRGeometryFactory::haveGEOS())
4202 : {
4203 0 : CPLError(CE_Failure, CPLE_AppDefined,
4204 : "OGRLayer::Identity() requires GEOS support");
4205 0 : return OGRERR_UNSUPPORTED_OPERATION;
4206 : }
4207 6 : if (bKeepLowerDimGeom)
4208 : {
4209 : // require that the result layer is of geom type unknown
4210 4 : if (pLayerResult->GetGeomType() != wkbUnknown)
4211 : {
4212 0 : CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO "
4213 : "since the result layer does not allow it.");
4214 0 : bKeepLowerDimGeom = FALSE;
4215 : }
4216 : }
4217 :
4218 : // get resources
4219 6 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4220 6 : if (ret != OGRERR_NONE)
4221 0 : goto done;
4222 6 : ret = create_field_map(poDefnInput, &mapInput);
4223 6 : if (ret != OGRERR_NONE)
4224 0 : goto done;
4225 6 : ret = create_field_map(poDefnMethod, &mapMethod);
4226 6 : if (ret != OGRERR_NONE)
4227 0 : goto done;
4228 6 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
4229 : mapMethod, true, papszOptions);
4230 6 : if (ret != OGRERR_NONE)
4231 0 : goto done;
4232 6 : poDefnResult = pLayerResult->GetLayerDefn();
4233 :
4234 : // split the features in input layer to the result layer
4235 18 : for (auto &&x : this)
4236 : {
4237 :
4238 12 : if (pfnProgress)
4239 : {
4240 2 : double p = progress_counter / progress_max;
4241 2 : if (p > progress_ticker)
4242 : {
4243 1 : if (!pfnProgress(p, "", pProgressArg))
4244 : {
4245 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4246 0 : ret = OGRERR_FAILURE;
4247 0 : goto done;
4248 : }
4249 : }
4250 2 : progress_counter += 1.0;
4251 : }
4252 :
4253 : // set up the filter on method layer
4254 12 : CPLErrorReset();
4255 : OGRGeometry *x_geom =
4256 12 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
4257 12 : if (CPLGetLastErrorType() != CE_None)
4258 : {
4259 0 : if (!bSkipFailures)
4260 : {
4261 0 : ret = OGRERR_FAILURE;
4262 0 : goto done;
4263 : }
4264 : else
4265 : {
4266 0 : CPLErrorReset();
4267 0 : ret = OGRERR_NONE;
4268 : }
4269 : }
4270 12 : if (!x_geom)
4271 : {
4272 0 : continue;
4273 : }
4274 :
4275 0 : OGRPreparedGeometryUniquePtr x_prepared_geom;
4276 12 : if (bUsePreparedGeometries)
4277 : {
4278 12 : x_prepared_geom.reset(
4279 : OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
4280 12 : if (!x_prepared_geom)
4281 : {
4282 0 : goto done;
4283 : }
4284 : }
4285 :
4286 : OGRGeometryUniquePtr x_geom_diff(
4287 : x_geom
4288 12 : ->clone()); // this will be the geometry of the result feature
4289 26 : for (auto &&y : pLayerMethod)
4290 : {
4291 14 : OGRGeometry *y_geom = y->GetGeometryRef();
4292 14 : if (!y_geom)
4293 0 : continue;
4294 :
4295 14 : CPLErrorReset();
4296 28 : if (x_prepared_geom &&
4297 14 : !(OGRPreparedGeometryIntersects(x_prepared_geom.get(),
4298 14 : OGRGeometry::ToHandle(y_geom))))
4299 : {
4300 0 : if (CPLGetLastErrorType() == CE_None)
4301 : {
4302 0 : continue;
4303 : }
4304 : }
4305 14 : if (CPLGetLastErrorType() != CE_None)
4306 : {
4307 0 : if (!bSkipFailures)
4308 : {
4309 0 : ret = OGRERR_FAILURE;
4310 0 : goto done;
4311 : }
4312 : else
4313 : {
4314 0 : CPLErrorReset();
4315 0 : ret = OGRERR_NONE;
4316 : }
4317 : }
4318 :
4319 14 : CPLErrorReset();
4320 14 : OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
4321 14 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
4322 : {
4323 0 : if (!bSkipFailures)
4324 : {
4325 0 : ret = OGRERR_FAILURE;
4326 0 : goto done;
4327 : }
4328 : else
4329 : {
4330 0 : CPLErrorReset();
4331 0 : ret = OGRERR_NONE;
4332 : }
4333 : }
4334 28 : else if (poIntersection->IsEmpty() ||
4335 14 : (!bKeepLowerDimGeom &&
4336 6 : (x_geom->getDimension() == y_geom->getDimension() &&
4337 6 : poIntersection->getDimension() <
4338 6 : x_geom->getDimension())))
4339 : {
4340 : /* ok*/
4341 : }
4342 : else
4343 : {
4344 10 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4345 10 : z->SetFieldsFrom(x.get(), mapInput);
4346 10 : z->SetFieldsFrom(y.get(), mapMethod);
4347 10 : if (bPromoteToMulti)
4348 2 : poIntersection.reset(
4349 : promote_to_multi(poIntersection.release()));
4350 10 : z->SetGeometryDirectly(poIntersection.release());
4351 10 : if (x_geom_diff)
4352 : {
4353 10 : CPLErrorReset();
4354 : OGRGeometryUniquePtr x_geom_diff_new(
4355 10 : x_geom_diff->Difference(y_geom));
4356 20 : if (CPLGetLastErrorType() != CE_None ||
4357 10 : x_geom_diff_new == nullptr)
4358 : {
4359 0 : if (!bSkipFailures)
4360 : {
4361 0 : ret = OGRERR_FAILURE;
4362 0 : goto done;
4363 : }
4364 : else
4365 : {
4366 0 : CPLErrorReset();
4367 : }
4368 : }
4369 : else
4370 : {
4371 10 : x_geom_diff.swap(x_geom_diff_new);
4372 : }
4373 : }
4374 10 : ret = pLayerResult->CreateFeature(z.get());
4375 10 : if (ret != OGRERR_NONE)
4376 : {
4377 0 : if (!bSkipFailures)
4378 : {
4379 0 : goto done;
4380 : }
4381 : else
4382 : {
4383 0 : CPLErrorReset();
4384 0 : ret = OGRERR_NONE;
4385 : }
4386 : }
4387 : }
4388 : }
4389 :
4390 12 : x_prepared_geom.reset();
4391 :
4392 12 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
4393 : {
4394 : /* ok */
4395 : }
4396 : else
4397 : {
4398 10 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4399 10 : z->SetFieldsFrom(x.get(), mapInput);
4400 10 : if (bPromoteToMulti)
4401 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
4402 10 : z->SetGeometryDirectly(x_geom_diff.release());
4403 10 : ret = pLayerResult->CreateFeature(z.get());
4404 10 : if (ret != OGRERR_NONE)
4405 : {
4406 0 : if (!bSkipFailures)
4407 : {
4408 0 : goto done;
4409 : }
4410 : else
4411 : {
4412 0 : CPLErrorReset();
4413 0 : ret = OGRERR_NONE;
4414 : }
4415 : }
4416 : }
4417 : }
4418 6 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4419 : {
4420 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4421 0 : ret = OGRERR_FAILURE;
4422 0 : goto done;
4423 : }
4424 6 : done:
4425 : // release resources
4426 6 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4427 6 : if (pGeometryMethodFilter)
4428 0 : delete pGeometryMethodFilter;
4429 6 : if (mapInput)
4430 3 : VSIFree(mapInput);
4431 6 : if (mapMethod)
4432 3 : VSIFree(mapMethod);
4433 6 : return ret;
4434 : }
4435 :
4436 : /************************************************************************/
4437 : /* OGR_L_Identity() */
4438 : /************************************************************************/
4439 :
4440 : /**
4441 : * \brief Identify the features of this layer with the ones from the
4442 : * identity layer.
4443 : *
4444 : * The result layer contains features whose geometries represent areas
4445 : * that are in the input layer. The features in the result layer have
4446 : * attributes from both input and method layers. The schema of the
4447 : * result layer can be set by the user or, if it is empty, is
4448 : * initialized to contain all fields in input and method layers.
4449 : *
4450 : * \note If the schema of the result is set by user and contains
4451 : * fields that have the same name as a field in input and in method
4452 : * layer, then the attribute in the result feature will get the value
4453 : * from the feature of the method layer (even if it is undefined).
4454 : *
4455 : * \note For best performance use the minimum amount of features in
4456 : * the method layer and copy it into a memory layer.
4457 : *
4458 : * \note This method relies on GEOS support. Do not use unless the
4459 : * GEOS support is compiled in.
4460 : *
4461 : * The recognized list of options is :
4462 : * <ul>
4463 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4464 : * feature could not be inserted or a GEOS call failed.
4465 : * </li>
4466 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4467 : * into MultiPolygons, LineStrings to MultiLineStrings or
4468 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4469 : * </li>
4470 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4471 : * will be created from the fields of the input layer.
4472 : * </li>
4473 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4474 : * will be created from the fields of the method layer.
4475 : * </li>
4476 : * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
4477 : * geometries to pretest intersection of features of method layer
4478 : * with features of this layer.
4479 : * </li>
4480 : * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
4481 : * result features with lower dimension geometry that would
4482 : * otherwise be added to the result layer. The default is YES, to add
4483 : * features with lower dimension geometry, but only if the result layer
4484 : * has an unknown geometry type.
4485 : * </li>
4486 : * </ul>
4487 : *
4488 : * This function is the same as the C++ method OGRLayer::Identity().
4489 : *
4490 : * @param pLayerInput the input layer. Should not be NULL.
4491 : *
4492 : * @param pLayerMethod the method layer. Should not be NULL.
4493 : *
4494 : * @param pLayerResult the layer where the features resulting from the
4495 : * operation are inserted. Should not be NULL. See above the note
4496 : * about the schema.
4497 : *
4498 : * @param papszOptions NULL terminated list of options (may be NULL).
4499 : *
4500 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4501 : * reporting progress or NULL.
4502 : *
4503 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4504 : *
4505 : * @return an error code if there was an error or the execution was
4506 : * interrupted, OGRERR_NONE otherwise.
4507 : *
4508 : * @note The first geometry field is always used.
4509 : *
4510 : * @since OGR 1.10
4511 : */
4512 :
4513 6 : OGRErr OGR_L_Identity(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
4514 : OGRLayerH pLayerResult, char **papszOptions,
4515 : GDALProgressFunc pfnProgress, void *pProgressArg)
4516 :
4517 : {
4518 6 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
4519 6 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
4520 6 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE);
4521 :
4522 : return OGRLayer::FromHandle(pLayerInput)
4523 6 : ->Identity(OGRLayer::FromHandle(pLayerMethod),
4524 : OGRLayer::FromHandle(pLayerResult), papszOptions,
4525 6 : pfnProgress, pProgressArg);
4526 : }
4527 :
4528 : /************************************************************************/
4529 : /* Update() */
4530 : /************************************************************************/
4531 :
4532 : /**
4533 : * \brief Update this layer with features from the update layer.
4534 : *
4535 : * The result layer contains features whose geometries represent areas
4536 : * that are either in the input layer or in the method layer. The
4537 : * features in the result layer have areas of the features of the
4538 : * method layer or those ares of the features of the input layer that
4539 : * are not covered by the method layer. The features of the result
4540 : * layer get their attributes from the input layer. The schema of the
4541 : * result layer can be set by the user or, if it is empty, is
4542 : * initialized to contain all fields in the input layer.
4543 : *
4544 : * \note If the schema of the result is set by user and contains
4545 : * fields that have the same name as a field in the method layer, then
4546 : * the attribute in the result feature the originates from the method
4547 : * layer will get the value from the feature of the method layer.
4548 : *
4549 : * \note For best performance use the minimum amount of features in
4550 : * the method layer and copy it into a memory layer.
4551 : *
4552 : * \note This method relies on GEOS support. Do not use unless the
4553 : * GEOS support is compiled in.
4554 : *
4555 : * The recognized list of options is :
4556 : * <ul>
4557 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4558 : * feature could not be inserted or a GEOS call failed.
4559 : * </li>
4560 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4561 : * into MultiPolygons, LineStrings to MultiLineStrings or
4562 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4563 : * </li>
4564 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4565 : * will be created from the fields of the input layer.
4566 : * </li>
4567 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4568 : * will be created from the fields of the method layer.
4569 : * </li>
4570 : * </ul>
4571 : *
4572 : * This method is the same as the C function OGR_L_Update().
4573 : *
4574 : * @param pLayerMethod the method layer. Should not be NULL.
4575 : *
4576 : * @param pLayerResult the layer where the features resulting from the
4577 : * operation are inserted. Should not be NULL. See above the note
4578 : * about the schema.
4579 : *
4580 : * @param papszOptions NULL terminated list of options (may be NULL).
4581 : *
4582 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4583 : * reporting progress or NULL.
4584 : *
4585 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4586 : *
4587 : * @return an error code if there was an error or the execution was
4588 : * interrupted, OGRERR_NONE otherwise.
4589 : *
4590 : * @note The first geometry field is always used.
4591 : *
4592 : * @since OGR 1.10
4593 : */
4594 :
4595 5 : OGRErr OGRLayer::Update(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
4596 : char **papszOptions, GDALProgressFunc pfnProgress,
4597 : void *pProgressArg)
4598 : {
4599 5 : OGRErr ret = OGRERR_NONE;
4600 5 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
4601 5 : OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
4602 5 : OGRFeatureDefn *poDefnResult = nullptr;
4603 5 : OGRGeometry *pGeometryMethodFilter = nullptr;
4604 5 : int *mapInput = nullptr;
4605 5 : int *mapMethod = nullptr;
4606 : double progress_max =
4607 5 : static_cast<double>(GetFeatureCount(FALSE)) +
4608 5 : static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
4609 5 : double progress_counter = 0;
4610 5 : double progress_ticker = 0;
4611 : const bool bSkipFailures =
4612 5 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4613 5 : const bool bPromoteToMulti = CPLTestBool(
4614 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4615 :
4616 : // check for GEOS
4617 5 : if (!OGRGeometryFactory::haveGEOS())
4618 : {
4619 0 : CPLError(CE_Failure, CPLE_AppDefined,
4620 : "OGRLayer::Update() requires GEOS support");
4621 0 : return OGRERR_UNSUPPORTED_OPERATION;
4622 : }
4623 :
4624 : // get resources
4625 5 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4626 5 : if (ret != OGRERR_NONE)
4627 0 : goto done;
4628 5 : ret = create_field_map(poDefnInput, &mapInput);
4629 5 : if (ret != OGRERR_NONE)
4630 0 : goto done;
4631 5 : ret = create_field_map(poDefnMethod, &mapMethod);
4632 5 : if (ret != OGRERR_NONE)
4633 0 : goto done;
4634 5 : ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput,
4635 : mapMethod, false, papszOptions);
4636 5 : if (ret != OGRERR_NONE)
4637 0 : goto done;
4638 5 : poDefnResult = pLayerResult->GetLayerDefn();
4639 :
4640 : // add clipped features from the input layer
4641 15 : for (auto &&x : this)
4642 : {
4643 :
4644 10 : if (pfnProgress)
4645 : {
4646 2 : double p = progress_counter / progress_max;
4647 2 : if (p > progress_ticker)
4648 : {
4649 1 : if (!pfnProgress(p, "", pProgressArg))
4650 : {
4651 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4652 0 : ret = OGRERR_FAILURE;
4653 0 : goto done;
4654 : }
4655 : }
4656 2 : progress_counter += 1.0;
4657 : }
4658 :
4659 : // set up the filter on method layer
4660 10 : CPLErrorReset();
4661 : OGRGeometry *x_geom =
4662 10 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
4663 10 : if (CPLGetLastErrorType() != CE_None)
4664 : {
4665 0 : if (!bSkipFailures)
4666 : {
4667 0 : ret = OGRERR_FAILURE;
4668 0 : goto done;
4669 : }
4670 : else
4671 : {
4672 0 : CPLErrorReset();
4673 0 : ret = OGRERR_NONE;
4674 : }
4675 : }
4676 10 : if (!x_geom)
4677 : {
4678 0 : continue;
4679 : }
4680 :
4681 : OGRGeometryUniquePtr x_geom_diff(
4682 10 : x_geom->clone()); // this will be the geometry of a result feature
4683 24 : for (auto &&y : pLayerMethod)
4684 : {
4685 14 : OGRGeometry *y_geom = y->GetGeometryRef();
4686 14 : if (!y_geom)
4687 0 : continue;
4688 14 : if (x_geom_diff)
4689 : {
4690 14 : CPLErrorReset();
4691 : OGRGeometryUniquePtr x_geom_diff_new(
4692 14 : x_geom_diff->Difference(y_geom));
4693 28 : if (CPLGetLastErrorType() != CE_None ||
4694 14 : x_geom_diff_new == nullptr)
4695 : {
4696 0 : if (!bSkipFailures)
4697 : {
4698 0 : ret = OGRERR_FAILURE;
4699 0 : goto done;
4700 : }
4701 : else
4702 : {
4703 0 : CPLErrorReset();
4704 0 : ret = OGRERR_NONE;
4705 : }
4706 : }
4707 : else
4708 : {
4709 14 : x_geom_diff.swap(x_geom_diff_new);
4710 : }
4711 : }
4712 : }
4713 :
4714 10 : if (x_geom_diff == nullptr || x_geom_diff->IsEmpty())
4715 : {
4716 : /* ok */
4717 : }
4718 : else
4719 : {
4720 6 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4721 6 : z->SetFieldsFrom(x.get(), mapInput);
4722 6 : if (bPromoteToMulti)
4723 2 : x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
4724 6 : z->SetGeometryDirectly(x_geom_diff.release());
4725 6 : ret = pLayerResult->CreateFeature(z.get());
4726 6 : if (ret != OGRERR_NONE)
4727 : {
4728 0 : if (!bSkipFailures)
4729 : {
4730 0 : goto done;
4731 : }
4732 : else
4733 : {
4734 0 : CPLErrorReset();
4735 0 : ret = OGRERR_NONE;
4736 : }
4737 : }
4738 : }
4739 : }
4740 :
4741 : // restore the original filter and add features from the update layer
4742 5 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4743 12 : for (auto &&y : pLayerMethod)
4744 : {
4745 :
4746 7 : if (pfnProgress)
4747 : {
4748 1 : double p = progress_counter / progress_max;
4749 1 : if (p > progress_ticker)
4750 : {
4751 1 : if (!pfnProgress(p, "", pProgressArg))
4752 : {
4753 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4754 0 : ret = OGRERR_FAILURE;
4755 0 : goto done;
4756 : }
4757 : }
4758 1 : progress_counter += 1.0;
4759 : }
4760 :
4761 7 : OGRGeometry *y_geom = y->StealGeometry();
4762 7 : if (!y_geom)
4763 0 : continue;
4764 7 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4765 7 : if (mapMethod)
4766 3 : z->SetFieldsFrom(y.get(), mapMethod);
4767 7 : z->SetGeometryDirectly(y_geom);
4768 7 : ret = pLayerResult->CreateFeature(z.get());
4769 7 : if (ret != OGRERR_NONE)
4770 : {
4771 0 : if (!bSkipFailures)
4772 : {
4773 0 : goto done;
4774 : }
4775 : else
4776 : {
4777 0 : CPLErrorReset();
4778 0 : ret = OGRERR_NONE;
4779 : }
4780 : }
4781 : }
4782 5 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
4783 : {
4784 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4785 0 : ret = OGRERR_FAILURE;
4786 0 : goto done;
4787 : }
4788 5 : done:
4789 : // release resources
4790 5 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4791 5 : if (pGeometryMethodFilter)
4792 0 : delete pGeometryMethodFilter;
4793 5 : if (mapInput)
4794 3 : VSIFree(mapInput);
4795 5 : if (mapMethod)
4796 3 : VSIFree(mapMethod);
4797 5 : return ret;
4798 : }
4799 :
4800 : /************************************************************************/
4801 : /* OGR_L_Update() */
4802 : /************************************************************************/
4803 :
4804 : /**
4805 : * \brief Update this layer with features from the update layer.
4806 : *
4807 : * The result layer contains features whose geometries represent areas
4808 : * that are either in the input layer or in the method layer. The
4809 : * features in the result layer have areas of the features of the
4810 : * method layer or those ares of the features of the input layer that
4811 : * are not covered by the method layer. The features of the result
4812 : * layer get their attributes from the input layer. The schema of the
4813 : * result layer can be set by the user or, if it is empty, is
4814 : * initialized to contain all fields in the input layer.
4815 : *
4816 : * \note If the schema of the result is set by user and contains
4817 : * fields that have the same name as a field in the method layer, then
4818 : * the attribute in the result feature the originates from the method
4819 : * layer will get the value from the feature of the method layer.
4820 : *
4821 : * \note For best performance use the minimum amount of features in
4822 : * the method layer and copy it into a memory layer.
4823 : *
4824 : * \note This method relies on GEOS support. Do not use unless the
4825 : * GEOS support is compiled in.
4826 : *
4827 : * The recognized list of options is :
4828 : * <ul>
4829 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4830 : * feature could not be inserted or a GEOS call failed.
4831 : * </li>
4832 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4833 : * into MultiPolygons, LineStrings to MultiLineStrings or
4834 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4835 : * </li>
4836 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4837 : * will be created from the fields of the input layer.
4838 : * </li>
4839 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4840 : * will be created from the fields of the method layer.
4841 : * </li>
4842 : * </ul>
4843 : *
4844 : * This function is the same as the C++ method OGRLayer::Update().
4845 : *
4846 : * @param pLayerInput the input layer. Should not be NULL.
4847 : *
4848 : * @param pLayerMethod the method layer. Should not be NULL.
4849 : *
4850 : * @param pLayerResult the layer where the features resulting from the
4851 : * operation are inserted. Should not be NULL. See above the note
4852 : * about the schema.
4853 : *
4854 : * @param papszOptions NULL terminated list of options (may be NULL).
4855 : *
4856 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4857 : * reporting progress or NULL.
4858 : *
4859 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4860 : *
4861 : * @return an error code if there was an error or the execution was
4862 : * interrupted, OGRERR_NONE otherwise.
4863 : *
4864 : * @note The first geometry field is always used.
4865 : *
4866 : * @since OGR 1.10
4867 : */
4868 :
4869 5 : OGRErr OGR_L_Update(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
4870 : OGRLayerH pLayerResult, char **papszOptions,
4871 : GDALProgressFunc pfnProgress, void *pProgressArg)
4872 :
4873 : {
4874 5 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE);
4875 5 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE);
4876 5 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE);
4877 :
4878 : return OGRLayer::FromHandle(pLayerInput)
4879 5 : ->Update(OGRLayer::FromHandle(pLayerMethod),
4880 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
4881 5 : pProgressArg);
4882 : }
4883 :
4884 : /************************************************************************/
4885 : /* Clip() */
4886 : /************************************************************************/
4887 :
4888 : /**
4889 : * \brief Clip off areas that are not covered by the method layer.
4890 : *
4891 : * The result layer contains features whose geometries represent areas
4892 : * that are in the input layer and in the method layer. The features
4893 : * in the result layer have the (possibly clipped) areas of features
4894 : * in the input layer and the attributes from the same features. The
4895 : * schema of the result layer can be set by the user or, if it is
4896 : * empty, is initialized to contain all fields in the input layer.
4897 : *
4898 : * \note For best performance use the minimum amount of features in
4899 : * the method layer and copy it into a memory layer.
4900 : *
4901 : * \note This method relies on GEOS support. Do not use unless the
4902 : * GEOS support is compiled in.
4903 : *
4904 : * The recognized list of options is :
4905 : * <ul>
4906 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4907 : * feature could not be inserted or a GEOS call failed.
4908 : * </li>
4909 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
4910 : * into MultiPolygons, LineStrings to MultiLineStrings or
4911 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
4912 : * </li>
4913 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4914 : * will be created from the fields of the input layer.
4915 : * </li>
4916 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4917 : * will be created from the fields of the method layer.
4918 : * </li>
4919 : * </ul>
4920 : *
4921 : * This method is the same as the C function OGR_L_Clip().
4922 : *
4923 : * @param pLayerMethod the method layer. Should not be NULL.
4924 : *
4925 : * @param pLayerResult the layer where the features resulting from the
4926 : * operation are inserted. Should not be NULL. See above the note
4927 : * about the schema.
4928 : *
4929 : * @param papszOptions NULL terminated list of options (may be NULL).
4930 : *
4931 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
4932 : * reporting progress or NULL.
4933 : *
4934 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4935 : *
4936 : * @return an error code if there was an error or the execution was
4937 : * interrupted, OGRERR_NONE otherwise.
4938 : *
4939 : * @note The first geometry field is always used.
4940 : *
4941 : * @since OGR 1.10
4942 : */
4943 :
4944 3 : OGRErr OGRLayer::Clip(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
4945 : char **papszOptions, GDALProgressFunc pfnProgress,
4946 : void *pProgressArg)
4947 : {
4948 3 : OGRErr ret = OGRERR_NONE;
4949 3 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
4950 3 : OGRFeatureDefn *poDefnResult = nullptr;
4951 3 : OGRGeometry *pGeometryMethodFilter = nullptr;
4952 3 : int *mapInput = nullptr;
4953 3 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
4954 3 : double progress_counter = 0;
4955 3 : double progress_ticker = 0;
4956 : const bool bSkipFailures =
4957 3 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4958 3 : const bool bPromoteToMulti = CPLTestBool(
4959 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4960 :
4961 : // check for GEOS
4962 3 : if (!OGRGeometryFactory::haveGEOS())
4963 : {
4964 0 : CPLError(CE_Failure, CPLE_AppDefined,
4965 : "OGRLayer::Clip() requires GEOS support");
4966 0 : return OGRERR_UNSUPPORTED_OPERATION;
4967 : }
4968 :
4969 3 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4970 3 : if (ret != OGRERR_NONE)
4971 0 : goto done;
4972 3 : ret = create_field_map(poDefnInput, &mapInput);
4973 3 : if (ret != OGRERR_NONE)
4974 0 : goto done;
4975 3 : ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
4976 : nullptr, false, papszOptions);
4977 3 : if (ret != OGRERR_NONE)
4978 0 : goto done;
4979 :
4980 3 : poDefnResult = pLayerResult->GetLayerDefn();
4981 9 : for (auto &&x : this)
4982 : {
4983 :
4984 6 : if (pfnProgress)
4985 : {
4986 2 : double p = progress_counter / progress_max;
4987 2 : if (p > progress_ticker)
4988 : {
4989 1 : if (!pfnProgress(p, "", pProgressArg))
4990 : {
4991 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4992 0 : ret = OGRERR_FAILURE;
4993 0 : goto done;
4994 : }
4995 : }
4996 2 : progress_counter += 1.0;
4997 : }
4998 :
4999 : // set up the filter on method layer
5000 6 : CPLErrorReset();
5001 : OGRGeometry *x_geom =
5002 6 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5003 6 : if (CPLGetLastErrorType() != CE_None)
5004 : {
5005 0 : if (!bSkipFailures)
5006 : {
5007 0 : ret = OGRERR_FAILURE;
5008 0 : goto done;
5009 : }
5010 : else
5011 : {
5012 0 : CPLErrorReset();
5013 0 : ret = OGRERR_NONE;
5014 : }
5015 : }
5016 6 : if (!x_geom)
5017 : {
5018 0 : continue;
5019 : }
5020 :
5021 : OGRGeometryUniquePtr
5022 0 : geom; // this will be the geometry of the result feature
5023 : // incrementally add area from y to geom
5024 12 : for (auto &&y : pLayerMethod)
5025 : {
5026 6 : OGRGeometry *y_geom = y->GetGeometryRef();
5027 6 : if (!y_geom)
5028 0 : continue;
5029 6 : if (!geom)
5030 : {
5031 6 : geom.reset(y_geom->clone());
5032 : }
5033 : else
5034 : {
5035 0 : CPLErrorReset();
5036 0 : OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
5037 0 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
5038 : {
5039 0 : if (!bSkipFailures)
5040 : {
5041 0 : ret = OGRERR_FAILURE;
5042 0 : goto done;
5043 : }
5044 : else
5045 : {
5046 0 : CPLErrorReset();
5047 0 : ret = OGRERR_NONE;
5048 : }
5049 : }
5050 : else
5051 : {
5052 0 : geom.swap(geom_new);
5053 : }
5054 : }
5055 : }
5056 :
5057 : // possibly add a new feature with area x intersection sum of y
5058 6 : if (geom)
5059 : {
5060 6 : CPLErrorReset();
5061 : OGRGeometryUniquePtr poIntersection(
5062 6 : x_geom->Intersection(geom.get()));
5063 6 : if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr)
5064 : {
5065 0 : if (!bSkipFailures)
5066 : {
5067 0 : ret = OGRERR_FAILURE;
5068 0 : goto done;
5069 : }
5070 : else
5071 : {
5072 0 : CPLErrorReset();
5073 0 : ret = OGRERR_NONE;
5074 : }
5075 : }
5076 6 : else if (!poIntersection->IsEmpty())
5077 : {
5078 6 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5079 6 : z->SetFieldsFrom(x.get(), mapInput);
5080 6 : if (bPromoteToMulti)
5081 2 : poIntersection.reset(
5082 : promote_to_multi(poIntersection.release()));
5083 6 : z->SetGeometryDirectly(poIntersection.release());
5084 6 : ret = pLayerResult->CreateFeature(z.get());
5085 6 : if (ret != OGRERR_NONE)
5086 : {
5087 0 : if (!bSkipFailures)
5088 : {
5089 0 : goto done;
5090 : }
5091 : else
5092 : {
5093 0 : CPLErrorReset();
5094 0 : ret = OGRERR_NONE;
5095 : }
5096 : }
5097 : }
5098 : }
5099 : }
5100 3 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5101 : {
5102 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5103 0 : ret = OGRERR_FAILURE;
5104 0 : goto done;
5105 : }
5106 3 : done:
5107 : // release resources
5108 3 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5109 3 : if (pGeometryMethodFilter)
5110 0 : delete pGeometryMethodFilter;
5111 3 : if (mapInput)
5112 3 : VSIFree(mapInput);
5113 3 : return ret;
5114 : }
5115 :
5116 : /************************************************************************/
5117 : /* OGR_L_Clip() */
5118 : /************************************************************************/
5119 :
5120 : /**
5121 : * \brief Clip off areas that are not covered by the method layer.
5122 : *
5123 : * The result layer contains features whose geometries represent areas
5124 : * that are in the input layer and in the method layer. The features
5125 : * in the result layer have the (possibly clipped) areas of features
5126 : * in the input layer and the attributes from the same features. The
5127 : * schema of the result layer can be set by the user or, if it is
5128 : * empty, is initialized to contain all fields in the input layer.
5129 : *
5130 : * \note For best performance use the minimum amount of features in
5131 : * the method layer and copy it into a memory layer.
5132 : *
5133 : * \note This method relies on GEOS support. Do not use unless the
5134 : * GEOS support is compiled in.
5135 : *
5136 : * The recognized list of options is :
5137 : * <ul>
5138 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5139 : * feature could not be inserted or a GEOS call failed.
5140 : * </li>
5141 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5142 : * into MultiPolygons, LineStrings to MultiLineStrings or
5143 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5144 : * </li>
5145 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5146 : * will be created from the fields of the input layer.
5147 : * </li>
5148 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5149 : * will be created from the fields of the method layer.
5150 : * </li>
5151 : * </ul>
5152 : *
5153 : * This function is the same as the C++ method OGRLayer::Clip().
5154 : *
5155 : * @param pLayerInput the input layer. Should not be NULL.
5156 : *
5157 : * @param pLayerMethod the method layer. Should not be NULL.
5158 : *
5159 : * @param pLayerResult the layer where the features resulting from the
5160 : * operation are inserted. Should not be NULL. See above the note
5161 : * about the schema.
5162 : *
5163 : * @param papszOptions NULL terminated list of options (may be NULL).
5164 : *
5165 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5166 : * reporting progress or NULL.
5167 : *
5168 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5169 : *
5170 : * @return an error code if there was an error or the execution was
5171 : * interrupted, OGRERR_NONE otherwise.
5172 : *
5173 : * @note The first geometry field is always used.
5174 : *
5175 : * @since OGR 1.10
5176 : */
5177 :
5178 3 : OGRErr OGR_L_Clip(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5179 : OGRLayerH pLayerResult, char **papszOptions,
5180 : GDALProgressFunc pfnProgress, void *pProgressArg)
5181 :
5182 : {
5183 3 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5184 3 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5185 3 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE);
5186 :
5187 : return OGRLayer::FromHandle(pLayerInput)
5188 3 : ->Clip(OGRLayer::FromHandle(pLayerMethod),
5189 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
5190 3 : pProgressArg);
5191 : }
5192 :
5193 : /************************************************************************/
5194 : /* Erase() */
5195 : /************************************************************************/
5196 :
5197 : /**
5198 : * \brief Remove areas that are covered by the method layer.
5199 : *
5200 : * The result layer contains features whose geometries represent areas
5201 : * that are in the input layer but not in the method layer. The
5202 : * features in the result layer have attributes from the input
5203 : * layer. The schema of the result layer can be set by the user or, if
5204 : * it is empty, is initialized to contain all fields in the input
5205 : * layer.
5206 : *
5207 : * \note For best performance use the minimum amount of features in
5208 : * the method layer and copy it into a memory layer.
5209 : *
5210 : * \note This method relies on GEOS support. Do not use unless the
5211 : * GEOS support is compiled in.
5212 : *
5213 : * The recognized list of options is :
5214 : * <ul>
5215 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5216 : * feature could not be inserted or a GEOS call failed.
5217 : * </li>
5218 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5219 : * into MultiPolygons, LineStrings to MultiLineStrings or
5220 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5221 : * </li>
5222 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5223 : * will be created from the fields of the input layer.
5224 : * </li>
5225 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5226 : * will be created from the fields of the method layer.
5227 : * </li>
5228 : * </ul>
5229 : *
5230 : * This method is the same as the C function OGR_L_Erase().
5231 : *
5232 : * @param pLayerMethod the method layer. Should not be NULL.
5233 : *
5234 : * @param pLayerResult the layer where the features resulting from the
5235 : * operation are inserted. Should not be NULL. See above the note
5236 : * about the schema.
5237 : *
5238 : * @param papszOptions NULL terminated list of options (may be NULL).
5239 : *
5240 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5241 : * reporting progress or NULL.
5242 : *
5243 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5244 : *
5245 : * @return an error code if there was an error or the execution was
5246 : * interrupted, OGRERR_NONE otherwise.
5247 : *
5248 : * @note The first geometry field is always used.
5249 : *
5250 : * @since OGR 1.10
5251 : */
5252 :
5253 6 : OGRErr OGRLayer::Erase(OGRLayer *pLayerMethod, OGRLayer *pLayerResult,
5254 : char **papszOptions, GDALProgressFunc pfnProgress,
5255 : void *pProgressArg)
5256 : {
5257 6 : OGRErr ret = OGRERR_NONE;
5258 6 : OGRFeatureDefn *poDefnInput = GetLayerDefn();
5259 6 : OGRFeatureDefn *poDefnResult = nullptr;
5260 6 : OGRGeometry *pGeometryMethodFilter = nullptr;
5261 6 : int *mapInput = nullptr;
5262 6 : double progress_max = static_cast<double>(GetFeatureCount(FALSE));
5263 6 : double progress_counter = 0;
5264 6 : double progress_ticker = 0;
5265 : const bool bSkipFailures =
5266 6 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
5267 6 : const bool bPromoteToMulti = CPLTestBool(
5268 : CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
5269 :
5270 : // check for GEOS
5271 6 : if (!OGRGeometryFactory::haveGEOS())
5272 : {
5273 0 : CPLError(CE_Failure, CPLE_AppDefined,
5274 : "OGRLayer::Erase() requires GEOS support");
5275 0 : return OGRERR_UNSUPPORTED_OPERATION;
5276 : }
5277 :
5278 : // get resources
5279 6 : ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
5280 6 : if (ret != OGRERR_NONE)
5281 0 : goto done;
5282 6 : ret = create_field_map(poDefnInput, &mapInput);
5283 6 : if (ret != OGRERR_NONE)
5284 0 : goto done;
5285 6 : ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput,
5286 : nullptr, false, papszOptions);
5287 6 : if (ret != OGRERR_NONE)
5288 0 : goto done;
5289 6 : poDefnResult = pLayerResult->GetLayerDefn();
5290 :
5291 18 : for (auto &&x : this)
5292 : {
5293 :
5294 12 : if (pfnProgress)
5295 : {
5296 2 : double p = progress_counter / progress_max;
5297 2 : if (p > progress_ticker)
5298 : {
5299 1 : if (!pfnProgress(p, "", pProgressArg))
5300 : {
5301 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5302 0 : ret = OGRERR_FAILURE;
5303 0 : goto done;
5304 : }
5305 : }
5306 2 : progress_counter += 1.0;
5307 : }
5308 :
5309 : // set up the filter on the method layer
5310 12 : CPLErrorReset();
5311 : OGRGeometry *x_geom =
5312 12 : set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
5313 12 : if (CPLGetLastErrorType() != CE_None)
5314 : {
5315 0 : if (!bSkipFailures)
5316 : {
5317 0 : ret = OGRERR_FAILURE;
5318 0 : goto done;
5319 : }
5320 : else
5321 : {
5322 0 : CPLErrorReset();
5323 0 : ret = OGRERR_NONE;
5324 : }
5325 : }
5326 12 : if (!x_geom)
5327 : {
5328 0 : continue;
5329 : }
5330 :
5331 : OGRGeometryUniquePtr geom(
5332 : x_geom
5333 12 : ->clone()); // this will be the geometry of the result feature
5334 : // incrementally erase y from geom
5335 19 : for (auto &&y : pLayerMethod)
5336 : {
5337 9 : OGRGeometry *y_geom = y->GetGeometryRef();
5338 9 : if (!y_geom)
5339 0 : continue;
5340 9 : CPLErrorReset();
5341 9 : OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
5342 9 : if (CPLGetLastErrorType() != CE_None || geom_new == nullptr)
5343 : {
5344 0 : if (!bSkipFailures)
5345 : {
5346 0 : ret = OGRERR_FAILURE;
5347 0 : goto done;
5348 : }
5349 : else
5350 : {
5351 0 : CPLErrorReset();
5352 0 : ret = OGRERR_NONE;
5353 : }
5354 : }
5355 : else
5356 : {
5357 9 : geom.swap(geom_new);
5358 9 : if (geom->IsEmpty())
5359 : {
5360 2 : break;
5361 : }
5362 : }
5363 : }
5364 :
5365 : // add a new feature if there is remaining area
5366 12 : if (!geom->IsEmpty())
5367 : {
5368 10 : OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
5369 10 : z->SetFieldsFrom(x.get(), mapInput);
5370 10 : if (bPromoteToMulti)
5371 4 : geom.reset(promote_to_multi(geom.release()));
5372 10 : z->SetGeometryDirectly(geom.release());
5373 10 : ret = pLayerResult->CreateFeature(z.get());
5374 10 : if (ret != OGRERR_NONE)
5375 : {
5376 0 : if (!bSkipFailures)
5377 : {
5378 0 : goto done;
5379 : }
5380 : else
5381 : {
5382 0 : CPLErrorReset();
5383 0 : ret = OGRERR_NONE;
5384 : }
5385 : }
5386 : }
5387 : }
5388 6 : if (pfnProgress && !pfnProgress(1.0, "", pProgressArg))
5389 : {
5390 0 : CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
5391 0 : ret = OGRERR_FAILURE;
5392 0 : goto done;
5393 : }
5394 6 : done:
5395 : // release resources
5396 6 : pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
5397 6 : if (pGeometryMethodFilter)
5398 0 : delete pGeometryMethodFilter;
5399 6 : if (mapInput)
5400 5 : VSIFree(mapInput);
5401 6 : return ret;
5402 : }
5403 :
5404 : /************************************************************************/
5405 : /* OGR_L_Erase() */
5406 : /************************************************************************/
5407 :
5408 : /**
5409 : * \brief Remove areas that are covered by the method layer.
5410 : *
5411 : * The result layer contains features whose geometries represent areas
5412 : * that are in the input layer but not in the method layer. The
5413 : * features in the result layer have attributes from the input
5414 : * layer. The schema of the result layer can be set by the user or, if
5415 : * it is empty, is initialized to contain all fields in the input
5416 : * layer.
5417 : *
5418 : * \note For best performance use the minimum amount of features in
5419 : * the method layer and copy it into a memory layer.
5420 : *
5421 : * \note This method relies on GEOS support. Do not use unless the
5422 : * GEOS support is compiled in.
5423 : *
5424 : * The recognized list of options is :
5425 : * <ul>
5426 : * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
5427 : * feature could not be inserted or a GEOS call failed.
5428 : * </li>
5429 : * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
5430 : * into MultiPolygons, LineStrings to MultiLineStrings or
5431 : * Points to MultiPoints (only since GDAL 3.9.2 for the later)
5432 : * </li>
5433 : * <li>INPUT_PREFIX=string. Set a prefix for the field names that
5434 : * will be created from the fields of the input layer.
5435 : * </li>
5436 : * <li>METHOD_PREFIX=string. Set a prefix for the field names that
5437 : * will be created from the fields of the method layer.
5438 : * </li>
5439 : * </ul>
5440 : *
5441 : * This function is the same as the C++ method OGRLayer::Erase().
5442 : *
5443 : * @param pLayerInput the input layer. Should not be NULL.
5444 : *
5445 : * @param pLayerMethod the method layer. Should not be NULL.
5446 : *
5447 : * @param pLayerResult the layer where the features resulting from the
5448 : * operation are inserted. Should not be NULL. See above the note
5449 : * about the schema.
5450 : *
5451 : * @param papszOptions NULL terminated list of options (may be NULL).
5452 : *
5453 : * @param pfnProgress a GDALProgressFunc() compatible callback function for
5454 : * reporting progress or NULL.
5455 : *
5456 : * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
5457 : *
5458 : * @return an error code if there was an error or the execution was
5459 : * interrupted, OGRERR_NONE otherwise.
5460 : *
5461 : * @note The first geometry field is always used.
5462 : *
5463 : * @since OGR 1.10
5464 : */
5465 :
5466 6 : OGRErr OGR_L_Erase(OGRLayerH pLayerInput, OGRLayerH pLayerMethod,
5467 : OGRLayerH pLayerResult, char **papszOptions,
5468 : GDALProgressFunc pfnProgress, void *pProgressArg)
5469 :
5470 : {
5471 6 : VALIDATE_POINTER1(pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
5472 6 : VALIDATE_POINTER1(pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
5473 6 : VALIDATE_POINTER1(pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE);
5474 :
5475 : return OGRLayer::FromHandle(pLayerInput)
5476 6 : ->Erase(OGRLayer::FromHandle(pLayerMethod),
5477 : OGRLayer::FromHandle(pLayerResult), papszOptions, pfnProgress,
5478 6 : pProgressArg);
5479 : }
5480 :
5481 : /************************************************************************/
5482 : /* OGRLayer::FeatureIterator::Private */
5483 : /************************************************************************/
5484 :
5485 : struct OGRLayer::FeatureIterator::Private
5486 : {
5487 : CPL_DISALLOW_COPY_ASSIGN(Private)
5488 35980 : Private() = default;
5489 :
5490 : OGRFeatureUniquePtr m_poFeature{};
5491 : OGRLayer *m_poLayer = nullptr;
5492 : bool m_bError = false;
5493 : bool m_bEOF = true;
5494 : };
5495 :
5496 : /************************************************************************/
5497 : /* OGRLayer::FeatureIterator::FeatureIterator() */
5498 : /************************************************************************/
5499 :
5500 35980 : OGRLayer::FeatureIterator::FeatureIterator(OGRLayer *poLayer, bool bStart)
5501 35980 : : m_poPrivate(new OGRLayer::FeatureIterator::Private())
5502 : {
5503 35980 : m_poPrivate->m_poLayer = poLayer;
5504 35980 : if (bStart)
5505 : {
5506 17990 : if (m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator)
5507 : {
5508 1 : CPLError(CE_Failure, CPLE_NotSupported,
5509 : "Only one feature iterator can be "
5510 : "active at a time");
5511 1 : m_poPrivate->m_bError = true;
5512 : }
5513 : else
5514 : {
5515 17989 : m_poPrivate->m_poLayer->ResetReading();
5516 35978 : m_poPrivate->m_poFeature.reset(
5517 17989 : m_poPrivate->m_poLayer->GetNextFeature());
5518 17989 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
5519 17989 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
5520 : }
5521 : }
5522 35980 : }
5523 :
5524 : /************************************************************************/
5525 : /* ~OGRLayer::FeatureIterator::FeatureIterator() */
5526 : /************************************************************************/
5527 :
5528 35980 : OGRLayer::FeatureIterator::~FeatureIterator()
5529 : {
5530 35980 : if (!m_poPrivate->m_bError && m_poPrivate->m_poLayer)
5531 35979 : m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
5532 35980 : }
5533 :
5534 : /************************************************************************/
5535 : /* operator*() */
5536 : /************************************************************************/
5537 :
5538 154227 : OGRFeatureUniquePtr &OGRLayer::FeatureIterator::operator*()
5539 : {
5540 154227 : return m_poPrivate->m_poFeature;
5541 : }
5542 :
5543 : /************************************************************************/
5544 : /* operator++() */
5545 : /************************************************************************/
5546 :
5547 153546 : OGRLayer::FeatureIterator &OGRLayer::FeatureIterator::operator++()
5548 : {
5549 153546 : m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
5550 153546 : m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
5551 153546 : return *this;
5552 : }
5553 :
5554 : /************************************************************************/
5555 : /* operator!=() */
5556 : /************************************************************************/
5557 :
5558 171536 : bool OGRLayer::FeatureIterator::operator!=(
5559 : const OGRLayer::FeatureIterator &it) const
5560 : {
5561 171536 : return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
5562 : }
5563 :
5564 : /************************************************************************/
5565 : /* begin() */
5566 : /************************************************************************/
5567 :
5568 17990 : OGRLayer::FeatureIterator OGRLayer::begin()
5569 : {
5570 17990 : return {this, true};
5571 : }
5572 :
5573 : /************************************************************************/
5574 : /* end() */
5575 : /************************************************************************/
5576 :
5577 17990 : OGRLayer::FeatureIterator OGRLayer::end()
5578 : {
5579 17990 : return {this, false};
5580 : }
5581 :
5582 : /************************************************************************/
5583 : /* OGRLayer::GetGeometryTypes() */
5584 : /************************************************************************/
5585 :
5586 : /** \brief Get actual geometry types found in features.
5587 : *
5588 : * This method iterates over features to retrieve their geometry types. This
5589 : * is mostly useful for layers that report a wkbUnknown geometry type with
5590 : * GetGeomType() or GetGeomFieldDefn(iGeomField)->GetType().
5591 : *
5592 : * By default this method returns an array of nEntryCount entries with each
5593 : * geometry type (in OGRGeometryTypeCounter::eGeomType) and the corresponding
5594 : * number of features (in OGRGeometryTypeCounter::nCount).
5595 : * Features without geometries are reported as eGeomType == wkbNone.
5596 : *
5597 : * The nFlagsGGT parameter can be a combination (with binary or operator) of the
5598 : * following hints:
5599 : * <ul>
5600 : * <li>OGR_GGT_COUNT_NOT_NEEDED: to indicate that only the set of geometry types
5601 : * matter, not the number of features per geometry type. Consequently the value
5602 : * of OGRGeometryTypeCounter::nCount should be ignored.</li>
5603 : * <li>OGR_GGT_STOP_IF_MIXED: to indicate that the implementation may stop
5604 : * iterating over features as soon as 2 different geometry types (not counting
5605 : * null geometries) are found. The value of OGRGeometryTypeCounter::nCount
5606 : * should be ignored (zero might be systematically reported by some
5607 : * implementations).</li> <li>OGR_GGT_GEOMCOLLECTIONZ_TINZ: to indicate that if
5608 : * a geometry is of type wkbGeometryCollection25D and its first sub-geometry is
5609 : * of type wkbTINZ, wkbTINZ should be reported as geometry type. This is mostly
5610 : * useful for the ESRI Shapefile and (Open)FileGDB drivers regarding MultiPatch
5611 : * geometries.</li>
5612 : * </ul>
5613 : *
5614 : * If the layer has no features, a non-NULL returned array with nEntryCount == 0
5615 : * will be returned.
5616 : *
5617 : * Spatial and/or attribute filters will be taken into account.
5618 : *
5619 : * This method will error out on a layer without geometry fields
5620 : * (GetGeomType() == wkbNone).
5621 : *
5622 : * A cancellation callback may be provided. The progress percentage it is called
5623 : * with is not relevant. The callback should return TRUE if processing should go
5624 : * on, or FALSE if it should be interrupted.
5625 : *
5626 : * @param iGeomField Geometry field index.
5627 : * @param nFlagsGGT Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
5628 : * OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
5629 : * @param[out] nEntryCountOut Number of entries in the returned array.
5630 : * @param pfnProgress Cancellation callback. May be NULL.
5631 : * @param pProgressData User data for the cancellation callback. May be NULL.
5632 : * @return an array of nEntryCount that must be freed with CPLFree(),
5633 : * or NULL in case of error
5634 : * @since GDAL 3.6
5635 : */
5636 : OGRGeometryTypeCounter *
5637 12 : OGRLayer::GetGeometryTypes(int iGeomField, int nFlagsGGT, int &nEntryCountOut,
5638 : GDALProgressFunc pfnProgress, void *pProgressData)
5639 : {
5640 12 : OGRFeatureDefn *poDefn = GetLayerDefn();
5641 12 : const int nGeomFieldCount = poDefn->GetGeomFieldCount();
5642 12 : if (iGeomField < 0 || iGeomField >= nGeomFieldCount)
5643 : {
5644 1 : CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for iGeomField");
5645 1 : nEntryCountOut = 0;
5646 1 : return nullptr;
5647 : }
5648 :
5649 : // Ignore all fields but the geometry one of interest
5650 22 : CPLStringList aosIgnoredFieldsRestore;
5651 22 : CPLStringList aosIgnoredFields;
5652 11 : const int nFieldCount = poDefn->GetFieldCount();
5653 33 : for (int iField = 0; iField < nFieldCount; iField++)
5654 : {
5655 22 : const auto poFieldDefn = poDefn->GetFieldDefn(iField);
5656 22 : const char *pszName = poFieldDefn->GetNameRef();
5657 22 : if (poFieldDefn->IsIgnored())
5658 10 : aosIgnoredFieldsRestore.AddString(pszName);
5659 22 : if (iField != iGeomField)
5660 11 : aosIgnoredFields.AddString(pszName);
5661 : }
5662 33 : for (int iField = 0; iField < nGeomFieldCount; iField++)
5663 : {
5664 22 : const auto poFieldDefn = poDefn->GetGeomFieldDefn(iField);
5665 22 : const char *pszName = poFieldDefn->GetNameRef();
5666 22 : if (poFieldDefn->IsIgnored())
5667 10 : aosIgnoredFieldsRestore.AddString(pszName);
5668 22 : if (iField != iGeomField)
5669 11 : aosIgnoredFields.AddString(pszName);
5670 : }
5671 11 : if (poDefn->IsStyleIgnored())
5672 0 : aosIgnoredFieldsRestore.AddString("OGR_STYLE");
5673 11 : aosIgnoredFields.AddString("OGR_STYLE");
5674 11 : SetIgnoredFields(aosIgnoredFields.List());
5675 :
5676 : // Iterate over features
5677 22 : std::map<OGRwkbGeometryType, int64_t> oMapCount;
5678 22 : std::set<OGRwkbGeometryType> oSetNotNull;
5679 11 : const bool bGeomCollectionZTInZ =
5680 11 : (nFlagsGGT & OGR_GGT_GEOMCOLLECTIONZ_TINZ) != 0;
5681 11 : const bool bStopIfMixed = (nFlagsGGT & OGR_GGT_STOP_IF_MIXED) != 0;
5682 11 : if (pfnProgress == GDALDummyProgress)
5683 0 : pfnProgress = nullptr;
5684 11 : bool bInterrupted = false;
5685 47 : for (auto &&poFeature : *this)
5686 : {
5687 36 : const auto poGeom = poFeature->GetGeomFieldRef(iGeomField);
5688 36 : if (poGeom == nullptr)
5689 : {
5690 18 : ++oMapCount[wkbNone];
5691 : }
5692 : else
5693 : {
5694 18 : auto eGeomType = poGeom->getGeometryType();
5695 18 : if (bGeomCollectionZTInZ && eGeomType == wkbGeometryCollection25D)
5696 : {
5697 1 : const auto poGC = poGeom->toGeometryCollection();
5698 1 : if (poGC->getNumGeometries() > 0)
5699 : {
5700 : auto eSubGeomType =
5701 1 : poGC->getGeometryRef(0)->getGeometryType();
5702 1 : if (eSubGeomType == wkbTINZ)
5703 1 : eGeomType = wkbTINZ;
5704 : }
5705 : }
5706 18 : ++oMapCount[eGeomType];
5707 18 : if (bStopIfMixed)
5708 : {
5709 4 : oSetNotNull.insert(eGeomType);
5710 4 : if (oSetNotNull.size() == 2)
5711 2 : break;
5712 : }
5713 : }
5714 34 : if (pfnProgress && !pfnProgress(0.0, "", pProgressData))
5715 : {
5716 1 : bInterrupted = true;
5717 1 : break;
5718 : }
5719 : }
5720 :
5721 : // Restore ignore fields state
5722 11 : SetIgnoredFields(aosIgnoredFieldsRestore.List());
5723 :
5724 11 : if (bInterrupted)
5725 : {
5726 1 : nEntryCountOut = 0;
5727 1 : return nullptr;
5728 : }
5729 :
5730 : // Format result
5731 10 : nEntryCountOut = static_cast<int>(oMapCount.size());
5732 : OGRGeometryTypeCounter *pasRet = static_cast<OGRGeometryTypeCounter *>(
5733 10 : CPLCalloc(1 + nEntryCountOut, sizeof(OGRGeometryTypeCounter)));
5734 10 : int i = 0;
5735 37 : for (const auto &oIter : oMapCount)
5736 : {
5737 27 : pasRet[i].eGeomType = oIter.first;
5738 27 : pasRet[i].nCount = oIter.second;
5739 27 : ++i;
5740 : }
5741 10 : return pasRet;
5742 : }
5743 :
5744 : /************************************************************************/
5745 : /* OGR_L_GetGeometryTypes() */
5746 : /************************************************************************/
5747 :
5748 : /** \brief Get actual geometry types found in features.
5749 : *
5750 : * See OGRLayer::GetGeometryTypes() for details.
5751 : *
5752 : * @param hLayer Layer.
5753 : * @param iGeomField Geometry field index.
5754 : * @param nFlags Hint flags. 0, or combination of OGR_GGT_COUNT_NOT_NEEDED,
5755 : * OGR_GGT_STOP_IF_MIXED, OGR_GGT_GEOMCOLLECTIONZ_TINZ
5756 : * @param[out] pnEntryCount Pointer to the number of entries in the returned
5757 : * array. Must not be NULL.
5758 : * @param pfnProgress Cancellation callback. May be NULL.
5759 : * @param pProgressData User data for the cancellation callback. May be NULL.
5760 : * @return an array of *pnEntryCount that must be freed with CPLFree(),
5761 : * or NULL in case of error
5762 : * @since GDAL 3.6
5763 : */
5764 54 : OGRGeometryTypeCounter *OGR_L_GetGeometryTypes(OGRLayerH hLayer, int iGeomField,
5765 : int nFlags, int *pnEntryCount,
5766 : GDALProgressFunc pfnProgress,
5767 : void *pProgressData)
5768 : {
5769 54 : VALIDATE_POINTER1(hLayer, "OGR_L_GetGeometryTypes", nullptr);
5770 54 : VALIDATE_POINTER1(pnEntryCount, "OGR_L_GetGeometryTypes", nullptr);
5771 :
5772 108 : return OGRLayer::FromHandle(hLayer)->GetGeometryTypes(
5773 54 : iGeomField, nFlags, *pnEntryCount, pfnProgress, pProgressData);
5774 : }
5775 :
5776 : /************************************************************************/
5777 : /* OGRLayer::GetSupportedSRSList() */
5778 : /************************************************************************/
5779 :
5780 : /** \brief Get the list of SRS supported.
5781 : *
5782 : * The base implementation of this method will return an empty list. Some
5783 : * drivers (OAPIF, WFS) may return a non-empty list.
5784 : *
5785 : * One of the SRS returned may be passed to SetActiveSRS() to change the
5786 : * active SRS.
5787 : *
5788 : * @param iGeomField Geometry field index.
5789 : * @return list of supported SRS.
5790 : * @since GDAL 3.7
5791 : */
5792 : const OGRLayer::GetSupportedSRSListRetType &
5793 176 : OGRLayer::GetSupportedSRSList(CPL_UNUSED int iGeomField)
5794 : {
5795 176 : static OGRLayer::GetSupportedSRSListRetType empty;
5796 176 : return empty;
5797 : }
5798 :
5799 : /************************************************************************/
5800 : /* OGR_L_GetSupportedSRSList() */
5801 : /************************************************************************/
5802 :
5803 : /** \brief Get the list of SRS supported.
5804 : *
5805 : * The base implementation of this method will return an empty list. Some
5806 : * drivers (OAPIF, WFS) may return a non-empty list.
5807 : *
5808 : * One of the SRS returned may be passed to SetActiveSRS() to change the
5809 : * active SRS.
5810 : *
5811 : * @param hLayer Layer.
5812 : * @param iGeomField Geometry field index.
5813 : * @param[out] pnCount Number of values in returned array. Must not be null.
5814 : * @return list of supported SRS, to be freed with OSRFreeSRSArray(), or
5815 : * nullptr
5816 : * @since GDAL 3.7
5817 : */
5818 4 : OGRSpatialReferenceH *OGR_L_GetSupportedSRSList(OGRLayerH hLayer,
5819 : int iGeomField, int *pnCount)
5820 : {
5821 4 : VALIDATE_POINTER1(hLayer, "OGR_L_GetSupportedSRSList", nullptr);
5822 4 : VALIDATE_POINTER1(pnCount, "OGR_L_GetSupportedSRSList", nullptr);
5823 :
5824 : const auto &srsList =
5825 4 : OGRLayer::FromHandle(hLayer)->GetSupportedSRSList(iGeomField);
5826 4 : *pnCount = static_cast<int>(srsList.size());
5827 4 : if (srsList.empty())
5828 : {
5829 2 : return nullptr;
5830 : }
5831 : OGRSpatialReferenceH *pahRet = static_cast<OGRSpatialReferenceH *>(
5832 2 : CPLMalloc((1 + srsList.size()) * sizeof(OGRSpatialReferenceH)));
5833 2 : size_t i = 0;
5834 7 : for (const auto &poSRS : srsList)
5835 : {
5836 5 : poSRS->Reference();
5837 5 : pahRet[i] = OGRSpatialReference::ToHandle(poSRS.get());
5838 5 : ++i;
5839 : }
5840 2 : pahRet[i] = nullptr;
5841 2 : return pahRet;
5842 : }
5843 :
5844 : /************************************************************************/
5845 : /* OGRLayer::SetActiveSRS() */
5846 : /************************************************************************/
5847 :
5848 : /** \brief Change the active SRS.
5849 : *
5850 : * The passed SRS must be in the list returned by GetSupportedSRSList()
5851 : * (the actual pointer may be different, but should be tested as identical
5852 : * with OGRSpatialReference::IsSame()).
5853 : *
5854 : * Changing the active SRS affects:
5855 : * <ul>
5856 : * <li>the SRS in which geometries of returned features are expressed,</li>
5857 : * <li>the SRS in which geometries of passed features (CreateFeature(),
5858 : * SetFeature()) are expressed,</li>
5859 : * <li>the SRS returned by GetSpatialRef() and
5860 : * GetGeomFieldDefn()->GetSpatialRef(),</li>
5861 : * <li>the SRS used to interpret SetSpatialFilter() values.</li>
5862 : * </ul>
5863 : * This also resets feature reading and the spatial filter.
5864 : * Note however that this does not modify the storage SRS of the features of
5865 : * geometries. Said otherwise, this setting is volatile and has no persistent
5866 : * effects after dataset reopening.
5867 : *
5868 : * @param iGeomField Geometry field index.
5869 : * @param poSRS SRS to use
5870 : * @return OGRERR_NONE in case of success, or OGRERR_FAILURE if
5871 : * the passed SRS is not in GetSupportedSRSList()
5872 : * @since GDAL 3.7
5873 : */
5874 1 : OGRErr OGRLayer::SetActiveSRS(CPL_UNUSED int iGeomField,
5875 : CPL_UNUSED const OGRSpatialReference *poSRS)
5876 : {
5877 1 : return OGRERR_FAILURE;
5878 : }
5879 :
5880 : /************************************************************************/
5881 : /* OGR_L_SetActiveSRS() */
5882 : /************************************************************************/
5883 :
5884 : /** \brief Change the active SRS.
5885 : *
5886 : * The passed SRS must be in the list returned by GetSupportedSRSList()
5887 : * (the actual pointer may be different, but should be tested as identical
5888 : * with OGRSpatialReference::IsSame()).
5889 : *
5890 : * Changing the active SRS affects:
5891 : * <ul>
5892 : * <li>the SRS in which geometries of returned features are expressed,</li>
5893 : * <li>the SRS in which geometries of passed features (CreateFeature(),
5894 : * SetFeature()) are expressed,</li>
5895 : * <li>the SRS returned by GetSpatialRef() and
5896 : * GetGeomFieldDefn()->GetSpatialRef(),</li>
5897 : * <li>the SRS used to interpret SetSpatialFilter() values.</li>
5898 : * </ul>
5899 : * This also resets feature reading and the spatial filter.
5900 : * Note however that this does not modify the storage SRS of the features of
5901 : * geometries. Said otherwise, this setting is volatile and has no persistent
5902 : * effects after dataset reopening.
5903 : *
5904 : * @param hLayer Layer.
5905 : * @param iGeomField Geometry field index.
5906 : * @param hSRS SRS to use
5907 : * @return OGRERR_NONE in case of success, OGRERR_FAILURE if
5908 : * the passed SRS is not in GetSupportedSRSList().
5909 : * @since GDAL 3.7
5910 : */
5911 9 : OGRErr OGR_L_SetActiveSRS(OGRLayerH hLayer, int iGeomField,
5912 : OGRSpatialReferenceH hSRS)
5913 : {
5914 9 : VALIDATE_POINTER1(hLayer, "OGR_L_SetActiveSRS", OGRERR_FAILURE);
5915 18 : return OGRLayer::FromHandle(hLayer)->SetActiveSRS(
5916 9 : iGeomField, OGRSpatialReference::FromHandle(hSRS));
5917 : }
5918 :
5919 : /************************************************************************/
5920 : /* GetDataset() */
5921 : /************************************************************************/
5922 :
5923 : /** Return the dataset associated with this layer.
5924 : *
5925 : * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
5926 : * have CreateLayer() capability. It may not be implemented in read-only
5927 : * drivers or out-of-tree drivers.
5928 : *
5929 : * It is currently only used by the GetRecordBatchSchema()
5930 : * method to retrieve the field domain associated with a field, to fill the
5931 : * dictionary field of a struct ArrowSchema.
5932 : * It is also used by CreateFieldFromArrowSchema() to determine which field
5933 : * types and subtypes are supported by the layer, by inspecting the driver
5934 : * metadata, and potentially use fallback types when needed.
5935 : *
5936 : * This method is the same as the C function OGR_L_GetDataset().
5937 : *
5938 : * @return dataset, or nullptr when unknown.
5939 : * @since GDAL 3.6
5940 : */
5941 1 : GDALDataset *OGRLayer::GetDataset()
5942 : {
5943 1 : return nullptr;
5944 : }
5945 :
5946 : /************************************************************************/
5947 : /* OGR_L_GetDataset() */
5948 : /************************************************************************/
5949 :
5950 : /** Return the dataset associated with this layer.
5951 : *
5952 : * As of GDAL 3.9, GetDataset() is implemented on all in-tree drivers that
5953 : * have CreateLayer() capability. It may not be implemented in read-only
5954 : * drivers or out-of-tree drivers.
5955 : *
5956 : * It is currently only used by the GetRecordBatchSchema()
5957 : * method to retrieve the field domain associated with a field, to fill the
5958 : * dictionary field of a struct ArrowSchema.
5959 : * It is also used by CreateFieldFromArrowSchema() to determine which field
5960 : * types and subtypes are supported by the layer, by inspecting the driver
5961 : * metadata, and potentially use fallback types when needed.
5962 : *
5963 : * This function is the same as the C++ method OGRLayer::GetDataset().
5964 : *
5965 : * @return dataset, or nullptr when unknown.
5966 : * @since GDAL 3.9
5967 : */
5968 268 : GDALDatasetH OGR_L_GetDataset(OGRLayerH hLayer)
5969 : {
5970 268 : VALIDATE_POINTER1(hLayer, "OGR_L_GetDataset", nullptr);
5971 268 : return GDALDataset::ToHandle(OGRLayer::FromHandle(hLayer)->GetDataset());
5972 : }
|