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  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  ****************************************************************************/
29 
30 #include "ogrsf_frmts.h"
31 #include "ogr_api.h"
32 #include "ogr_p.h"
33 #include "ogr_attrind.h"
34 #include "ogr_swq.h"
35 #include "ograpispy.h"
36 
37 CPL_CVSID("$Id: ogrlayer.cpp e620b541e9c5d62487fa9dbcf42c8ce2f10b4905 2020-12-04 13:56:44 +0100 Even Rouault $")
38 
39 struct OGRLayer::Private
40 {
41     bool         m_bInFeatureIterator = false;
42 };
43 
44 /************************************************************************/
45 /*                              OGRLayer()                              */
46 /************************************************************************/
47 
OGRLayer()48 OGRLayer::OGRLayer() :
49     m_poPrivate(new Private()),
50     m_bFilterIsEnvelope(FALSE),
51     m_poFilterGeom(nullptr),
52     m_pPreparedFilterGeom(nullptr),
53     m_sFilterEnvelope{},
54     m_iGeomFieldFilter(0),
55     m_poStyleTable(nullptr),
56     m_poAttrQuery(nullptr),
57     m_pszAttrQueryString(nullptr),
58     m_poAttrIndex(nullptr),
59     m_nRefCount(0),
60     m_nFeaturesRead(0)
61 {}
62 
63 /************************************************************************/
64 /*                             ~OGRLayer()                              */
65 /************************************************************************/
66 
~OGRLayer()67 OGRLayer::~OGRLayer()
68 
69 {
70     if( m_poStyleTable )
71     {
72         delete m_poStyleTable;
73         m_poStyleTable = nullptr;
74     }
75 
76     if( m_poAttrIndex != nullptr )
77     {
78         delete m_poAttrIndex;
79         m_poAttrIndex = nullptr;
80     }
81 
82     if( m_poAttrQuery != nullptr )
83     {
84         delete m_poAttrQuery;
85         m_poAttrQuery = nullptr;
86     }
87 
88     CPLFree( m_pszAttrQueryString );
89 
90     if( m_poFilterGeom )
91     {
92         delete m_poFilterGeom;
93         m_poFilterGeom = nullptr;
94     }
95 
96     if( m_pPreparedFilterGeom != nullptr )
97     {
98         OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
99         m_pPreparedFilterGeom = nullptr;
100     }
101 }
102 
103 /************************************************************************/
104 /*                             Reference()                              */
105 /************************************************************************/
106 
Reference()107 int OGRLayer::Reference()
108 
109 {
110     return ++m_nRefCount;
111 }
112 
113 /************************************************************************/
114 /*                          OGR_L_Reference()                           */
115 /************************************************************************/
116 
OGR_L_Reference(OGRLayerH hLayer)117 int OGR_L_Reference( OGRLayerH hLayer )
118 
119 {
120     VALIDATE_POINTER1( hLayer, "OGR_L_Reference", 0 );
121 
122     return OGRLayer::FromHandle(hLayer)->Reference();
123 }
124 
125 /************************************************************************/
126 /*                            Dereference()                             */
127 /************************************************************************/
128 
Dereference()129 int OGRLayer::Dereference()
130 
131 {
132     return --m_nRefCount;
133 }
134 
135 /************************************************************************/
136 /*                         OGR_L_Dereference()                          */
137 /************************************************************************/
138 
OGR_L_Dereference(OGRLayerH hLayer)139 int OGR_L_Dereference( OGRLayerH hLayer )
140 
141 {
142     VALIDATE_POINTER1( hLayer, "OGR_L_Dereference", 0 );
143 
144     return OGRLayer::FromHandle(hLayer)->Dereference();
145 }
146 
147 /************************************************************************/
148 /*                            GetRefCount()                             */
149 /************************************************************************/
150 
GetRefCount() const151 int OGRLayer::GetRefCount() const
152 
153 {
154     return m_nRefCount;
155 }
156 
157 /************************************************************************/
158 /*                         OGR_L_GetRefCount()                          */
159 /************************************************************************/
160 
OGR_L_GetRefCount(OGRLayerH hLayer)161 int OGR_L_GetRefCount( OGRLayerH hLayer )
162 
163 {
164     VALIDATE_POINTER1( hLayer, "OGR_L_GetRefCount", 0 );
165 
166     return OGRLayer::FromHandle(hLayer)->GetRefCount();
167 }
168 
169 /************************************************************************/
170 /*                         GetFeatureCount()                            */
171 /************************************************************************/
172 
GetFeatureCount(int bForce)173 GIntBig OGRLayer::GetFeatureCount( int bForce )
174 
175 {
176     if( !bForce )
177         return -1;
178 
179     GIntBig nFeatureCount = 0;
180     for( auto&& poFeature: *this )
181     {
182         CPL_IGNORE_RET_VAL(poFeature.get());
183         nFeatureCount ++;
184     }
185     ResetReading();
186 
187     return nFeatureCount;
188 }
189 
190 /************************************************************************/
191 /*                      OGR_L_GetFeatureCount()                         */
192 /************************************************************************/
193 
OGR_L_GetFeatureCount(OGRLayerH hLayer,int bForce)194 GIntBig OGR_L_GetFeatureCount( OGRLayerH hLayer, int bForce )
195 
196 {
197     VALIDATE_POINTER1( hLayer, "OGR_L_GetFeatureCount", 0 );
198 
199 #ifdef OGRAPISPY_ENABLED
200     if( bOGRAPISpyEnabled )
201         OGRAPISpy_L_GetFeatureCount(hLayer, bForce);
202 #endif
203 
204     return OGRLayer::FromHandle(hLayer)->GetFeatureCount(bForce);
205 }
206 
207 /************************************************************************/
208 /*                             GetExtent()                              */
209 /************************************************************************/
210 
GetExtent(OGREnvelope * psExtent,int bForce)211 OGRErr OGRLayer::GetExtent(OGREnvelope *psExtent, int bForce )
212 
213 {
214     return GetExtentInternal(0, psExtent, bForce);
215 }
216 
GetExtent(int iGeomField,OGREnvelope * psExtent,int bForce)217 OGRErr OGRLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce )
218 
219 {
220     if( iGeomField == 0 )
221         return GetExtent(psExtent, bForce);
222     else
223         return GetExtentInternal(iGeomField, psExtent, bForce);
224 }
225 
226 //! @cond Doxygen_Suppress
GetExtentInternal(int iGeomField,OGREnvelope * psExtent,int bForce)227 OGRErr OGRLayer::GetExtentInternal(int iGeomField, OGREnvelope *psExtent, int bForce )
228 
229 {
230     psExtent->MinX = 0.0;
231     psExtent->MaxX = 0.0;
232     psExtent->MinY = 0.0;
233     psExtent->MaxY = 0.0;
234 
235 /* -------------------------------------------------------------------- */
236 /*      If this layer has a none geometry type, then we can             */
237 /*      reasonably assume there are not extents available.              */
238 /* -------------------------------------------------------------------- */
239     if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() ||
240         GetLayerDefn()->GetGeomFieldDefn(iGeomField)->GetType() == wkbNone )
241     {
242         if( iGeomField != 0 )
243         {
244             CPLError(CE_Failure, CPLE_AppDefined,
245                      "Invalid geometry field index : %d", iGeomField);
246         }
247         return OGRERR_FAILURE;
248     }
249 
250 /* -------------------------------------------------------------------- */
251 /*      If not forced, we should avoid having to scan all the           */
252 /*      features and just return a failure.                             */
253 /* -------------------------------------------------------------------- */
254     if( !bForce )
255         return OGRERR_FAILURE;
256 
257 /* -------------------------------------------------------------------- */
258 /*      OK, we hate to do this, but go ahead and read through all       */
259 /*      the features to collect geometries and build extents.           */
260 /* -------------------------------------------------------------------- */
261     OGREnvelope oEnv;
262     bool bExtentSet = false;
263 
264     for( auto&& poFeature: *this )
265     {
266         OGRGeometry *poGeom = poFeature->GetGeomFieldRef(iGeomField);
267         if (poGeom == nullptr || poGeom->IsEmpty())
268         {
269             /* Do nothing */
270         }
271         else if (!bExtentSet)
272         {
273             poGeom->getEnvelope(psExtent);
274             if( !(CPLIsNan(psExtent->MinX) || CPLIsNan(psExtent->MinY) ||
275                   CPLIsNan(psExtent->MaxX) || CPLIsNan(psExtent->MaxY)) )
276             {
277                 bExtentSet = true;
278             }
279         }
280         else
281         {
282             poGeom->getEnvelope(&oEnv);
283             if (oEnv.MinX < psExtent->MinX)
284                 psExtent->MinX = oEnv.MinX;
285             if (oEnv.MinY < psExtent->MinY)
286                 psExtent->MinY = oEnv.MinY;
287             if (oEnv.MaxX > psExtent->MaxX)
288                 psExtent->MaxX = oEnv.MaxX;
289             if (oEnv.MaxY > psExtent->MaxY)
290                 psExtent->MaxY = oEnv.MaxY;
291         }
292     }
293     ResetReading();
294 
295     return bExtentSet ? OGRERR_NONE : OGRERR_FAILURE;
296 }
297 //! @endcond
298 
299 /************************************************************************/
300 /*                          OGR_L_GetExtent()                           */
301 /************************************************************************/
302 
OGR_L_GetExtent(OGRLayerH hLayer,OGREnvelope * psExtent,int bForce)303 OGRErr OGR_L_GetExtent( OGRLayerH hLayer, OGREnvelope *psExtent, int bForce )
304 
305 {
306     VALIDATE_POINTER1( hLayer, "OGR_L_GetExtent", OGRERR_INVALID_HANDLE );
307 
308 #ifdef OGRAPISPY_ENABLED
309     if( bOGRAPISpyEnabled )
310         OGRAPISpy_L_GetExtent(hLayer, bForce);
311 #endif
312 
313     return OGRLayer::FromHandle(hLayer)->GetExtent( psExtent, bForce );
314 }
315 
316 /************************************************************************/
317 /*                         OGR_L_GetExtentEx()                          */
318 /************************************************************************/
319 
OGR_L_GetExtentEx(OGRLayerH hLayer,int iGeomField,OGREnvelope * psExtent,int bForce)320 OGRErr OGR_L_GetExtentEx( OGRLayerH hLayer, int iGeomField,
321                           OGREnvelope *psExtent, int bForce )
322 
323 {
324     VALIDATE_POINTER1( hLayer, "OGR_L_GetExtentEx", OGRERR_INVALID_HANDLE );
325 
326 #ifdef OGRAPISPY_ENABLED
327     if( bOGRAPISpyEnabled )
328         OGRAPISpy_L_GetExtentEx(hLayer, iGeomField, bForce);
329 #endif
330 
331     return OGRLayer::FromHandle(hLayer)->GetExtent( iGeomField, psExtent, bForce );
332 }
333 
334 /************************************************************************/
335 /*                         SetAttributeFilter()                         */
336 /************************************************************************/
337 
SetAttributeFilter(const char * pszQuery)338 OGRErr OGRLayer::SetAttributeFilter( const char *pszQuery )
339 
340 {
341     CPLFree(m_pszAttrQueryString);
342     m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
343 
344 /* -------------------------------------------------------------------- */
345 /*      Are we just clearing any existing query?                        */
346 /* -------------------------------------------------------------------- */
347     if( pszQuery == nullptr || strlen(pszQuery) == 0 )
348     {
349         if( m_poAttrQuery )
350         {
351             delete m_poAttrQuery;
352             m_poAttrQuery = nullptr;
353             ResetReading();
354         }
355         return OGRERR_NONE;
356     }
357 
358 /* -------------------------------------------------------------------- */
359 /*      Or are we installing a new query?                               */
360 /* -------------------------------------------------------------------- */
361     OGRErr      eErr;
362 
363     if( !m_poAttrQuery )
364         m_poAttrQuery = new OGRFeatureQuery();
365 
366     eErr = m_poAttrQuery->Compile( this, pszQuery );
367     if( eErr != OGRERR_NONE )
368     {
369         delete m_poAttrQuery;
370         m_poAttrQuery = nullptr;
371     }
372 
373     ResetReading();
374 
375     return eErr;
376 }
377 
378 /************************************************************************/
379 /*                        ContainGeomSpecialField()                     */
380 /************************************************************************/
381 
ContainGeomSpecialField(swq_expr_node * expr,int nLayerFieldCount)382 static int ContainGeomSpecialField(swq_expr_node* expr,
383                                    int nLayerFieldCount)
384 {
385     if (expr->eNodeType == SNT_COLUMN)
386     {
387         if( expr->table_index == 0 && expr->field_index != -1 )
388         {
389             int nSpecialFieldIdx = expr->field_index -
390                                     nLayerFieldCount;
391             return nSpecialFieldIdx == SPF_OGR_GEOMETRY ||
392                    nSpecialFieldIdx == SPF_OGR_GEOM_WKT ||
393                    nSpecialFieldIdx == SPF_OGR_GEOM_AREA;
394         }
395     }
396     else if (expr->eNodeType == SNT_OPERATION)
397     {
398         for( int i = 0; i < expr->nSubExprCount; i++ )
399         {
400             if (ContainGeomSpecialField(expr->papoSubExpr[i],
401                                         nLayerFieldCount))
402                 return TRUE;
403         }
404     }
405     return FALSE;
406 }
407 
408 /************************************************************************/
409 /*                AttributeFilterEvaluationNeedsGeometry()              */
410 /************************************************************************/
411 
412 //! @cond Doxygen_Suppress
AttributeFilterEvaluationNeedsGeometry()413 int OGRLayer::AttributeFilterEvaluationNeedsGeometry()
414 {
415     if( !m_poAttrQuery )
416         return FALSE;
417 
418     swq_expr_node* expr = static_cast<swq_expr_node *>(
419         m_poAttrQuery->GetSWQExpr());
420     int nLayerFieldCount = GetLayerDefn()->GetFieldCount();
421 
422     return ContainGeomSpecialField(expr, nLayerFieldCount);
423 }
424 //! @endcond
425 
426 /************************************************************************/
427 /*                      OGR_L_SetAttributeFilter()                      */
428 /************************************************************************/
429 
OGR_L_SetAttributeFilter(OGRLayerH hLayer,const char * pszQuery)430 OGRErr OGR_L_SetAttributeFilter( OGRLayerH hLayer, const char *pszQuery )
431 
432 {
433     VALIDATE_POINTER1( hLayer, "OGR_L_SetAttributeFilter", OGRERR_INVALID_HANDLE );
434 
435 #ifdef OGRAPISPY_ENABLED
436     if( bOGRAPISpyEnabled )
437         OGRAPISpy_L_SetAttributeFilter(hLayer, pszQuery);
438 #endif
439 
440     return OGRLayer::FromHandle(hLayer)->SetAttributeFilter( pszQuery );
441 }
442 
443 /************************************************************************/
444 /*                             GetFeature()                             */
445 /************************************************************************/
446 
GetFeature(GIntBig nFID)447 OGRFeature *OGRLayer::GetFeature( GIntBig nFID )
448 
449 {
450     /* Save old attribute and spatial filters */
451     char* pszOldFilter = m_pszAttrQueryString ? CPLStrdup(m_pszAttrQueryString) : nullptr;
452     OGRGeometry* poOldFilterGeom = ( m_poFilterGeom != nullptr ) ? m_poFilterGeom->clone() : nullptr;
453     int iOldGeomFieldFilter = m_iGeomFieldFilter;
454     /* Unset filters */
455     SetAttributeFilter(nullptr);
456     SetSpatialFilter(0, nullptr);
457 
458     OGRFeatureUniquePtr poFeature;
459     for( auto&& poFeatureIter: *this )
460     {
461         if( poFeatureIter->GetFID() == nFID )
462         {
463             poFeature.swap(poFeatureIter);
464             break;
465         }
466     }
467 
468     /* Restore filters */
469     SetAttributeFilter(pszOldFilter);
470     CPLFree(pszOldFilter);
471     SetSpatialFilter(iOldGeomFieldFilter, poOldFilterGeom);
472     delete poOldFilterGeom;
473 
474     return poFeature.release();
475 }
476 
477 /************************************************************************/
478 /*                          OGR_L_GetFeature()                          */
479 /************************************************************************/
480 
OGR_L_GetFeature(OGRLayerH hLayer,GIntBig nFeatureId)481 OGRFeatureH OGR_L_GetFeature( OGRLayerH hLayer, GIntBig nFeatureId )
482 
483 {
484     VALIDATE_POINTER1( hLayer, "OGR_L_GetFeature", nullptr );
485 
486 #ifdef OGRAPISPY_ENABLED
487     if( bOGRAPISpyEnabled )
488         OGRAPISpy_L_GetFeature(hLayer, nFeatureId);
489 #endif
490 
491     return OGRFeature::ToHandle(
492             OGRLayer::FromHandle(hLayer)->GetFeature( nFeatureId ));
493 }
494 
495 /************************************************************************/
496 /*                           SetNextByIndex()                           */
497 /************************************************************************/
498 
SetNextByIndex(GIntBig nIndex)499 OGRErr OGRLayer::SetNextByIndex( GIntBig nIndex )
500 
501 {
502     if( nIndex < 0 )
503         return OGRERR_FAILURE;
504 
505     ResetReading();
506 
507     OGRFeature *poFeature = nullptr;
508     while( nIndex-- > 0 )
509     {
510         poFeature = GetNextFeature();
511         if( poFeature == nullptr )
512             return OGRERR_FAILURE;
513 
514         delete poFeature;
515     }
516 
517     return OGRERR_NONE;
518 }
519 
520 /************************************************************************/
521 /*                        OGR_L_SetNextByIndex()                        */
522 /************************************************************************/
523 
OGR_L_SetNextByIndex(OGRLayerH hLayer,GIntBig nIndex)524 OGRErr OGR_L_SetNextByIndex( OGRLayerH hLayer, GIntBig nIndex )
525 
526 {
527     VALIDATE_POINTER1( hLayer, "OGR_L_SetNextByIndex", OGRERR_INVALID_HANDLE );
528 
529 #ifdef OGRAPISPY_ENABLED
530     if( bOGRAPISpyEnabled )
531         OGRAPISpy_L_SetNextByIndex(hLayer, nIndex);
532 #endif
533 
534     return OGRLayer::FromHandle(hLayer)->SetNextByIndex( nIndex );
535 }
536 
537 /************************************************************************/
538 /*                        OGR_L_GetNextFeature()                        */
539 /************************************************************************/
540 
OGR_L_GetNextFeature(OGRLayerH hLayer)541 OGRFeatureH OGR_L_GetNextFeature( OGRLayerH hLayer )
542 
543 {
544     VALIDATE_POINTER1( hLayer, "OGR_L_GetNextFeature", nullptr );
545 
546 #ifdef OGRAPISPY_ENABLED
547     if( bOGRAPISpyEnabled )
548         OGRAPISpy_L_GetNextFeature(hLayer);
549 #endif
550 
551     return OGRFeature::ToHandle(
552                 OGRLayer::FromHandle(hLayer)->GetNextFeature());
553 }
554 
555 /************************************************************************/
556 /*                       ConvertGeomsIfNecessary()                      */
557 /************************************************************************/
558 
ConvertGeomsIfNecessary(OGRFeature * poFeature)559 void OGRLayer::ConvertGeomsIfNecessary( OGRFeature *poFeature )
560 {
561     const bool bSupportsCurve = CPL_TO_BOOL(TestCapability(OLCCurveGeometries));
562     const bool bSupportsM = CPL_TO_BOOL(TestCapability(OLCMeasuredGeometries));
563     if( !bSupportsCurve || !bSupportsM )
564     {
565         int nGeomFieldCount = GetLayerDefn()->GetGeomFieldCount();
566         for(int i=0;i<nGeomFieldCount;i++)
567         {
568             OGRGeometry* poGeom = poFeature->GetGeomFieldRef(i);
569             if( poGeom != nullptr && (!bSupportsM && OGR_GT_HasM(poGeom->getGeometryType())) )
570             {
571                 poGeom->setMeasured(FALSE);
572             }
573             if( poGeom != nullptr && (!bSupportsCurve && OGR_GT_IsNonLinear(poGeom->getGeometryType())) )
574             {
575                 OGRwkbGeometryType eTargetType = OGR_GT_GetLinear(poGeom->getGeometryType());
576                 poFeature->SetGeomFieldDirectly(i,
577                     OGRGeometryFactory::forceTo(poFeature->StealGeometry(i), eTargetType));
578             }
579         }
580     }
581 }
582 
583 /************************************************************************/
584 /*                             SetFeature()                             */
585 /************************************************************************/
586 
SetFeature(OGRFeature * poFeature)587 OGRErr OGRLayer::SetFeature( OGRFeature *poFeature )
588 
589 {
590     ConvertGeomsIfNecessary(poFeature);
591     return ISetFeature(poFeature);
592 }
593 
594 /************************************************************************/
595 /*                             ISetFeature()                            */
596 /************************************************************************/
597 
ISetFeature(OGRFeature *)598 OGRErr OGRLayer::ISetFeature( OGRFeature * )
599 
600 {
601     return OGRERR_UNSUPPORTED_OPERATION;
602 }
603 
604 /************************************************************************/
605 /*                          OGR_L_SetFeature()                          */
606 /************************************************************************/
607 
OGR_L_SetFeature(OGRLayerH hLayer,OGRFeatureH hFeat)608 OGRErr OGR_L_SetFeature( OGRLayerH hLayer, OGRFeatureH hFeat )
609 
610 {
611     VALIDATE_POINTER1( hLayer, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE );
612     VALIDATE_POINTER1( hFeat, "OGR_L_SetFeature", OGRERR_INVALID_HANDLE );
613 
614 #ifdef OGRAPISPY_ENABLED
615     if( bOGRAPISpyEnabled )
616         OGRAPISpy_L_SetFeature(hLayer, hFeat);
617 #endif
618 
619     return OGRLayer::FromHandle(hLayer)->SetFeature( OGRFeature::FromHandle(hFeat) );
620 }
621 
622 /************************************************************************/
623 /*                           CreateFeature()                            */
624 /************************************************************************/
625 
CreateFeature(OGRFeature * poFeature)626 OGRErr OGRLayer::CreateFeature( OGRFeature *poFeature )
627 
628 {
629     ConvertGeomsIfNecessary(poFeature);
630     return ICreateFeature(poFeature);
631 }
632 
633 /************************************************************************/
634 /*                           ICreateFeature()                            */
635 /************************************************************************/
636 
ICreateFeature(OGRFeature *)637 OGRErr OGRLayer::ICreateFeature( OGRFeature * )
638 
639 {
640     return OGRERR_UNSUPPORTED_OPERATION;
641 }
642 
643 /************************************************************************/
644 /*                        OGR_L_CreateFeature()                         */
645 /************************************************************************/
646 
OGR_L_CreateFeature(OGRLayerH hLayer,OGRFeatureH hFeat)647 OGRErr OGR_L_CreateFeature( OGRLayerH hLayer, OGRFeatureH hFeat )
648 
649 {
650     VALIDATE_POINTER1( hLayer, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE );
651     VALIDATE_POINTER1( hFeat, "OGR_L_CreateFeature", OGRERR_INVALID_HANDLE );
652 
653 #ifdef OGRAPISPY_ENABLED
654     if( bOGRAPISpyEnabled )
655         OGRAPISpy_L_CreateFeature(hLayer, hFeat);
656 #endif
657 
658     return OGRLayer::FromHandle(hLayer)->CreateFeature( OGRFeature::FromHandle(hFeat) );
659 }
660 
661 /************************************************************************/
662 /*                            CreateField()                             */
663 /************************************************************************/
664 
CreateField(OGRFieldDefn * poField,int bApproxOK)665 OGRErr OGRLayer::CreateField( OGRFieldDefn * poField, int bApproxOK )
666 
667 {
668     (void) poField;
669     (void) bApproxOK;
670 
671     CPLError( CE_Failure, CPLE_NotSupported,
672               "CreateField() not supported by this layer.\n" );
673 
674     return OGRERR_UNSUPPORTED_OPERATION;
675 }
676 
677 /************************************************************************/
678 /*                         OGR_L_CreateField()                          */
679 /************************************************************************/
680 
OGR_L_CreateField(OGRLayerH hLayer,OGRFieldDefnH hField,int bApproxOK)681 OGRErr OGR_L_CreateField( OGRLayerH hLayer, OGRFieldDefnH hField,
682                           int bApproxOK )
683 
684 {
685     VALIDATE_POINTER1( hLayer, "OGR_L_CreateField", OGRERR_INVALID_HANDLE );
686     VALIDATE_POINTER1( hField, "OGR_L_CreateField", OGRERR_INVALID_HANDLE );
687 
688 #ifdef OGRAPISPY_ENABLED
689     if( bOGRAPISpyEnabled )
690         OGRAPISpy_L_CreateField(hLayer, hField, bApproxOK);
691 #endif
692 
693     return OGRLayer::FromHandle(hLayer)->CreateField( OGRFieldDefn::FromHandle(hField),
694                                                bApproxOK );
695 }
696 
697 /************************************************************************/
698 /*                            DeleteField()                             */
699 /************************************************************************/
700 
DeleteField(int iField)701 OGRErr OGRLayer::DeleteField( int iField )
702 
703 {
704     (void) iField;
705 
706     CPLError( CE_Failure, CPLE_NotSupported,
707               "DeleteField() not supported by this layer.\n" );
708 
709     return OGRERR_UNSUPPORTED_OPERATION;
710 }
711 
712 /************************************************************************/
713 /*                         OGR_L_DeleteField()                          */
714 /************************************************************************/
715 
OGR_L_DeleteField(OGRLayerH hLayer,int iField)716 OGRErr OGR_L_DeleteField( OGRLayerH hLayer, int iField )
717 
718 {
719     VALIDATE_POINTER1( hLayer, "OGR_L_DeleteField", OGRERR_INVALID_HANDLE );
720 
721 #ifdef OGRAPISPY_ENABLED
722     if( bOGRAPISpyEnabled )
723         OGRAPISpy_L_DeleteField(hLayer, iField);
724 #endif
725 
726     return OGRLayer::FromHandle(hLayer)->DeleteField( iField );
727 }
728 
729 /************************************************************************/
730 /*                           ReorderFields()                            */
731 /************************************************************************/
732 
ReorderFields(int * panMap)733 OGRErr OGRLayer::ReorderFields( int* panMap )
734 
735 {
736     (void) panMap;
737 
738     CPLError( CE_Failure, CPLE_NotSupported,
739               "ReorderFields() not supported by this layer.\n" );
740 
741     return OGRERR_UNSUPPORTED_OPERATION;
742 }
743 
744 /************************************************************************/
745 /*                       OGR_L_ReorderFields()                          */
746 /************************************************************************/
747 
OGR_L_ReorderFields(OGRLayerH hLayer,int * panMap)748 OGRErr OGR_L_ReorderFields( OGRLayerH hLayer, int* panMap )
749 
750 {
751     VALIDATE_POINTER1( hLayer, "OGR_L_ReorderFields", OGRERR_INVALID_HANDLE );
752 
753 #ifdef OGRAPISPY_ENABLED
754     if( bOGRAPISpyEnabled )
755         OGRAPISpy_L_ReorderFields(hLayer, panMap);
756 #endif
757 
758     return OGRLayer::FromHandle(hLayer)->ReorderFields( panMap );
759 }
760 
761 /************************************************************************/
762 /*                            ReorderField()                            */
763 /************************************************************************/
764 
ReorderField(int iOldFieldPos,int iNewFieldPos)765 OGRErr OGRLayer::ReorderField( int iOldFieldPos, int iNewFieldPos )
766 
767 {
768     OGRErr eErr;
769 
770     int nFieldCount = GetLayerDefn()->GetFieldCount();
771 
772     if (iOldFieldPos < 0 || iOldFieldPos >= nFieldCount)
773     {
774         CPLError( CE_Failure, CPLE_NotSupported,
775                   "Invalid field index");
776         return OGRERR_FAILURE;
777     }
778     if (iNewFieldPos < 0 || iNewFieldPos >= nFieldCount)
779     {
780         CPLError( CE_Failure, CPLE_NotSupported,
781                   "Invalid field index");
782         return OGRERR_FAILURE;
783     }
784     if (iNewFieldPos == iOldFieldPos)
785         return OGRERR_NONE;
786 
787     int* panMap = static_cast<int*>(CPLMalloc(sizeof(int) * nFieldCount));
788     if (iOldFieldPos < iNewFieldPos)
789     {
790         /* "0","1","2","3","4" (1,3) -> "0","2","3","1","4" */
791         int i = 0;  // Used after for.
792         for( ; i < iOldFieldPos; i++ )
793             panMap[i] = i;
794         for( ; i < iNewFieldPos; i++ )
795             panMap[i] = i + 1;
796         panMap[iNewFieldPos] = iOldFieldPos;
797         for( i = iNewFieldPos + 1; i < nFieldCount; i++ )
798             panMap[i] = i;
799     }
800     else
801     {
802         /* "0","1","2","3","4" (3,1) -> "0","3","1","2","4" */
803         for( int i = 0; i < iNewFieldPos; i++ )
804             panMap[i] = i;
805         panMap[iNewFieldPos] = iOldFieldPos;
806         int i = iNewFieldPos+1;  // Used after for.
807         for( ; i <= iOldFieldPos; i++ )
808             panMap[i] = i - 1;
809         for( ; i < nFieldCount; i++ )
810             panMap[i] = i;
811     }
812 
813     eErr = ReorderFields(panMap);
814 
815     CPLFree(panMap);
816 
817     return eErr;
818 }
819 
820 /************************************************************************/
821 /*                        OGR_L_ReorderField()                          */
822 /************************************************************************/
823 
OGR_L_ReorderField(OGRLayerH hLayer,int iOldFieldPos,int iNewFieldPos)824 OGRErr OGR_L_ReorderField( OGRLayerH hLayer, int iOldFieldPos, int iNewFieldPos )
825 
826 {
827     VALIDATE_POINTER1( hLayer, "OGR_L_ReorderField", OGRERR_INVALID_HANDLE );
828 
829 #ifdef OGRAPISPY_ENABLED
830     if( bOGRAPISpyEnabled )
831         OGRAPISpy_L_ReorderField(hLayer, iOldFieldPos, iNewFieldPos);
832 #endif
833 
834     return OGRLayer::FromHandle(hLayer)->ReorderField( iOldFieldPos, iNewFieldPos );
835 }
836 
837 /************************************************************************/
838 /*                           AlterFieldDefn()                           */
839 /************************************************************************/
840 
AlterFieldDefn(int,OGRFieldDefn *,int)841 OGRErr OGRLayer::AlterFieldDefn( int /* iField*/,
842                                  OGRFieldDefn* /*poNewFieldDefn*/,
843                                  int /* nFlags */ )
844 
845 {
846     CPLError( CE_Failure, CPLE_NotSupported,
847               "AlterFieldDefn() not supported by this layer.\n" );
848 
849     return OGRERR_UNSUPPORTED_OPERATION;
850 }
851 
852 /************************************************************************/
853 /*                        OGR_L_AlterFieldDefn()                        */
854 /************************************************************************/
855 
OGR_L_AlterFieldDefn(OGRLayerH hLayer,int iField,OGRFieldDefnH hNewFieldDefn,int nFlags)856 OGRErr OGR_L_AlterFieldDefn( OGRLayerH hLayer, int iField, OGRFieldDefnH hNewFieldDefn,
857                              int nFlags )
858 
859 {
860     VALIDATE_POINTER1( hLayer, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE );
861     VALIDATE_POINTER1( hNewFieldDefn, "OGR_L_AlterFieldDefn", OGRERR_INVALID_HANDLE );
862 
863 #ifdef OGRAPISPY_ENABLED
864     if( bOGRAPISpyEnabled )
865         OGRAPISpy_L_AlterFieldDefn(hLayer, iField, hNewFieldDefn, nFlags);
866 #endif
867 
868     return OGRLayer::FromHandle(hLayer)->AlterFieldDefn( iField,
869                             OGRFieldDefn::FromHandle(hNewFieldDefn), nFlags );
870 }
871 
872 /************************************************************************/
873 /*                         CreateGeomField()                            */
874 /************************************************************************/
875 
CreateGeomField(OGRGeomFieldDefn * poField,int bApproxOK)876 OGRErr OGRLayer::CreateGeomField( OGRGeomFieldDefn * poField, int bApproxOK )
877 
878 {
879     (void) poField;
880     (void) bApproxOK;
881 
882     CPLError( CE_Failure, CPLE_NotSupported,
883               "CreateGeomField() not supported by this layer.\n" );
884 
885     return OGRERR_UNSUPPORTED_OPERATION;
886 }
887 
888 /************************************************************************/
889 /*                        OGR_L_CreateGeomField()                       */
890 /************************************************************************/
891 
OGR_L_CreateGeomField(OGRLayerH hLayer,OGRGeomFieldDefnH hField,int bApproxOK)892 OGRErr OGR_L_CreateGeomField( OGRLayerH hLayer, OGRGeomFieldDefnH hField,
893                               int bApproxOK )
894 
895 {
896     VALIDATE_POINTER1( hLayer, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE );
897     VALIDATE_POINTER1( hField, "OGR_L_CreateGeomField", OGRERR_INVALID_HANDLE );
898 
899 #ifdef OGRAPISPY_ENABLED
900     if( bOGRAPISpyEnabled )
901         OGRAPISpy_L_CreateGeomField(hLayer, hField, bApproxOK);
902 #endif
903 
904     return OGRLayer::FromHandle(hLayer)->CreateGeomField(
905         OGRGeomFieldDefn::FromHandle(hField), bApproxOK );
906 }
907 
908 /************************************************************************/
909 /*                          StartTransaction()                          */
910 /************************************************************************/
911 
StartTransaction()912 OGRErr OGRLayer::StartTransaction()
913 
914 {
915     return OGRERR_NONE;
916 }
917 
918 /************************************************************************/
919 /*                       OGR_L_StartTransaction()                       */
920 /************************************************************************/
921 
OGR_L_StartTransaction(OGRLayerH hLayer)922 OGRErr OGR_L_StartTransaction( OGRLayerH hLayer )
923 
924 {
925     VALIDATE_POINTER1( hLayer, "OGR_L_StartTransaction", OGRERR_INVALID_HANDLE );
926 
927 #ifdef OGRAPISPY_ENABLED
928     if( bOGRAPISpyEnabled )
929         OGRAPISpy_L_StartTransaction(hLayer);
930 #endif
931 
932     return OGRLayer::FromHandle(hLayer)->StartTransaction();
933 }
934 
935 /************************************************************************/
936 /*                         CommitTransaction()                          */
937 /************************************************************************/
938 
CommitTransaction()939 OGRErr OGRLayer::CommitTransaction()
940 
941 {
942     return OGRERR_NONE;
943 }
944 
945 /************************************************************************/
946 /*                       OGR_L_CommitTransaction()                      */
947 /************************************************************************/
948 
OGR_L_CommitTransaction(OGRLayerH hLayer)949 OGRErr OGR_L_CommitTransaction( OGRLayerH hLayer )
950 
951 {
952     VALIDATE_POINTER1( hLayer, "OGR_L_CommitTransaction", OGRERR_INVALID_HANDLE );
953 
954 #ifdef OGRAPISPY_ENABLED
955     if( bOGRAPISpyEnabled )
956         OGRAPISpy_L_CommitTransaction(hLayer);
957 #endif
958 
959     return OGRLayer::FromHandle(hLayer)->CommitTransaction();
960 }
961 
962 /************************************************************************/
963 /*                        RollbackTransaction()                         */
964 /************************************************************************/
965 
RollbackTransaction()966 OGRErr OGRLayer::RollbackTransaction()
967 
968 {
969     return OGRERR_UNSUPPORTED_OPERATION;
970 }
971 
972 /************************************************************************/
973 /*                     OGR_L_RollbackTransaction()                      */
974 /************************************************************************/
975 
OGR_L_RollbackTransaction(OGRLayerH hLayer)976 OGRErr OGR_L_RollbackTransaction( OGRLayerH hLayer )
977 
978 {
979     VALIDATE_POINTER1( hLayer, "OGR_L_RollbackTransaction", OGRERR_INVALID_HANDLE );
980 
981 #ifdef OGRAPISPY_ENABLED
982     if( bOGRAPISpyEnabled )
983         OGRAPISpy_L_RollbackTransaction(hLayer);
984 #endif
985 
986     return OGRLayer::FromHandle(hLayer)->RollbackTransaction();
987 }
988 
989 /************************************************************************/
990 /*                         OGR_L_GetLayerDefn()                         */
991 /************************************************************************/
992 
OGR_L_GetLayerDefn(OGRLayerH hLayer)993 OGRFeatureDefnH OGR_L_GetLayerDefn( OGRLayerH hLayer )
994 
995 {
996     VALIDATE_POINTER1( hLayer, "OGR_L_GetLayerDefn", nullptr );
997 
998 #ifdef OGRAPISPY_ENABLED
999     if( bOGRAPISpyEnabled )
1000         OGRAPISpy_L_GetLayerDefn(hLayer);
1001 #endif
1002 
1003     return OGRFeatureDefn::ToHandle(
1004             OGRLayer::FromHandle(hLayer)->GetLayerDefn());
1005 }
1006 
1007 /************************************************************************/
1008 /*                         OGR_L_FindFieldIndex()                       */
1009 /************************************************************************/
1010 
OGR_L_FindFieldIndex(OGRLayerH hLayer,const char * pszFieldName,int bExactMatch)1011 int OGR_L_FindFieldIndex( OGRLayerH hLayer, const char *pszFieldName, int bExactMatch )
1012 
1013 {
1014     VALIDATE_POINTER1( hLayer, "OGR_L_FindFieldIndex", -1 );
1015 
1016 #ifdef OGRAPISPY_ENABLED
1017     if( bOGRAPISpyEnabled )
1018         OGRAPISpy_L_FindFieldIndex(hLayer, pszFieldName, bExactMatch);
1019 #endif
1020 
1021     return OGRLayer::FromHandle(hLayer)->FindFieldIndex( pszFieldName, bExactMatch );
1022 }
1023 
1024 /************************************************************************/
1025 /*                           FindFieldIndex()                           */
1026 /************************************************************************/
1027 
FindFieldIndex(const char * pszFieldName,CPL_UNUSED int bExactMatch)1028 int OGRLayer::FindFieldIndex( const char *pszFieldName, CPL_UNUSED int bExactMatch )
1029 {
1030     return GetLayerDefn()->GetFieldIndex( pszFieldName );
1031 }
1032 
1033 /************************************************************************/
1034 /*                           GetSpatialRef()                            */
1035 /************************************************************************/
1036 
GetSpatialRef()1037 OGRSpatialReference *OGRLayer::GetSpatialRef()
1038 {
1039     if( GetLayerDefn()->GetGeomFieldCount() > 0 )
1040         return GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef();
1041     else
1042         return nullptr;
1043 }
1044 
1045 /************************************************************************/
1046 /*                        OGR_L_GetSpatialRef()                         */
1047 /************************************************************************/
1048 
OGR_L_GetSpatialRef(OGRLayerH hLayer)1049 OGRSpatialReferenceH OGR_L_GetSpatialRef( OGRLayerH hLayer )
1050 
1051 {
1052     VALIDATE_POINTER1( hLayer, "OGR_L_GetSpatialRef", nullptr );
1053 
1054 #ifdef OGRAPISPY_ENABLED
1055     if( bOGRAPISpyEnabled )
1056         OGRAPISpy_L_GetSpatialRef(hLayer);
1057 #endif
1058 
1059     return OGRSpatialReference::ToHandle(
1060             OGRLayer::FromHandle(hLayer)->GetSpatialRef());
1061 }
1062 
1063 /************************************************************************/
1064 /*                        OGR_L_TestCapability()                        */
1065 /************************************************************************/
1066 
OGR_L_TestCapability(OGRLayerH hLayer,const char * pszCap)1067 int OGR_L_TestCapability( OGRLayerH hLayer, const char *pszCap )
1068 
1069 {
1070     VALIDATE_POINTER1( hLayer, "OGR_L_TestCapability", 0 );
1071     VALIDATE_POINTER1( pszCap, "OGR_L_TestCapability", 0 );
1072 
1073 #ifdef OGRAPISPY_ENABLED
1074     if( bOGRAPISpyEnabled )
1075         OGRAPISpy_L_TestCapability(hLayer, pszCap);
1076 #endif
1077 
1078     return OGRLayer::FromHandle(hLayer)->TestCapability( pszCap );
1079 }
1080 
1081 /************************************************************************/
1082 /*                          GetSpatialFilter()                          */
1083 /************************************************************************/
1084 
GetSpatialFilter()1085 OGRGeometry *OGRLayer::GetSpatialFilter()
1086 
1087 {
1088     return m_poFilterGeom;
1089 }
1090 
1091 /************************************************************************/
1092 /*                       OGR_L_GetSpatialFilter()                       */
1093 /************************************************************************/
1094 
OGR_L_GetSpatialFilter(OGRLayerH hLayer)1095 OGRGeometryH OGR_L_GetSpatialFilter( OGRLayerH hLayer )
1096 
1097 {
1098     VALIDATE_POINTER1( hLayer, "OGR_L_GetSpatialFilter", nullptr );
1099 
1100 #ifdef OGRAPISPY_ENABLED
1101     if( bOGRAPISpyEnabled )
1102         OGRAPISpy_L_GetSpatialFilter(hLayer);
1103 #endif
1104 
1105     return OGRGeometry::ToHandle(
1106             OGRLayer::FromHandle(hLayer)->GetSpatialFilter());
1107 }
1108 
1109 /************************************************************************/
1110 /*                          SetSpatialFilter()                          */
1111 /************************************************************************/
1112 
SetSpatialFilter(OGRGeometry * poGeomIn)1113 void OGRLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
1114 
1115 {
1116     m_iGeomFieldFilter = 0;
1117     if( InstallFilter( poGeomIn ) )
1118         ResetReading();
1119 }
1120 
SetSpatialFilter(int iGeomField,OGRGeometry * poGeomIn)1121 void OGRLayer::SetSpatialFilter( int iGeomField, OGRGeometry * poGeomIn )
1122 
1123 {
1124     if( iGeomField == 0 )
1125     {
1126         m_iGeomFieldFilter = iGeomField;
1127         SetSpatialFilter( poGeomIn );
1128     }
1129     else
1130     {
1131         if( iGeomField < 0 || iGeomField >= GetLayerDefn()->GetGeomFieldCount() )
1132         {
1133             CPLError(CE_Failure, CPLE_AppDefined,
1134                      "Invalid geometry field index : %d", iGeomField);
1135             return;
1136         }
1137 
1138         m_iGeomFieldFilter = iGeomField;
1139         if( InstallFilter( poGeomIn ) )
1140             ResetReading();
1141     }
1142 }
1143 
1144 /************************************************************************/
1145 /*                       OGR_L_SetSpatialFilter()                       */
1146 /************************************************************************/
1147 
OGR_L_SetSpatialFilter(OGRLayerH hLayer,OGRGeometryH hGeom)1148 void OGR_L_SetSpatialFilter( OGRLayerH hLayer, OGRGeometryH hGeom )
1149 
1150 {
1151     VALIDATE_POINTER0( hLayer, "OGR_L_SetSpatialFilter" );
1152 
1153 #ifdef OGRAPISPY_ENABLED
1154     if( bOGRAPISpyEnabled )
1155         OGRAPISpy_L_SetSpatialFilter(hLayer, hGeom);
1156 #endif
1157 
1158     OGRLayer::FromHandle(hLayer)->SetSpatialFilter(
1159         OGRGeometry::FromHandle(hGeom) );
1160 }
1161 
1162 /************************************************************************/
1163 /*                      OGR_L_SetSpatialFilterEx()                      */
1164 /************************************************************************/
1165 
OGR_L_SetSpatialFilterEx(OGRLayerH hLayer,int iGeomField,OGRGeometryH hGeom)1166 void OGR_L_SetSpatialFilterEx( OGRLayerH hLayer, int iGeomField,
1167                                OGRGeometryH hGeom )
1168 
1169 {
1170     VALIDATE_POINTER0( hLayer, "OGR_L_SetSpatialFilterEx" );
1171 
1172 #ifdef OGRAPISPY_ENABLED
1173     if( bOGRAPISpyEnabled )
1174         OGRAPISpy_L_SetSpatialFilterEx(hLayer, iGeomField, hGeom);
1175 #endif
1176 
1177     OGRLayer::FromHandle(hLayer)->SetSpatialFilter( iGeomField,
1178                                             OGRGeometry::FromHandle(hGeom) );
1179 }
1180 /************************************************************************/
1181 /*                        SetSpatialFilterRect()                        */
1182 /************************************************************************/
1183 
SetSpatialFilterRect(double dfMinX,double dfMinY,double dfMaxX,double dfMaxY)1184 void OGRLayer::SetSpatialFilterRect( double dfMinX, double dfMinY,
1185                                      double dfMaxX, double dfMaxY )
1186 
1187 {
1188     SetSpatialFilterRect( 0, dfMinX, dfMinY, dfMaxX, dfMaxY );
1189 }
1190 
SetSpatialFilterRect(int iGeomField,double dfMinX,double dfMinY,double dfMaxX,double dfMaxY)1191 void OGRLayer::SetSpatialFilterRect( int iGeomField,
1192                                      double dfMinX, double dfMinY,
1193                                      double dfMaxX, double dfMaxY )
1194 
1195 {
1196     OGRLinearRing  oRing;
1197     OGRPolygon oPoly;
1198 
1199     oRing.addPoint( dfMinX, dfMinY );
1200     oRing.addPoint( dfMinX, dfMaxY );
1201     oRing.addPoint( dfMaxX, dfMaxY );
1202     oRing.addPoint( dfMaxX, dfMinY );
1203     oRing.addPoint( dfMinX, dfMinY );
1204 
1205     oPoly.addRing( &oRing );
1206 
1207     if( iGeomField == 0 )
1208         /* for drivers that only overload SetSpatialFilter(OGRGeometry*) */
1209         SetSpatialFilter( &oPoly );
1210     else
1211         SetSpatialFilter( iGeomField, &oPoly );
1212 }
1213 
1214 /************************************************************************/
1215 /*                     OGR_L_SetSpatialFilterRect()                     */
1216 /************************************************************************/
1217 
OGR_L_SetSpatialFilterRect(OGRLayerH hLayer,double dfMinX,double dfMinY,double dfMaxX,double dfMaxY)1218 void OGR_L_SetSpatialFilterRect( OGRLayerH hLayer,
1219                                  double dfMinX, double dfMinY,
1220                                  double dfMaxX, double dfMaxY )
1221 
1222 {
1223     VALIDATE_POINTER0( hLayer, "OGR_L_SetSpatialFilterRect" );
1224 
1225 #ifdef OGRAPISPY_ENABLED
1226     if( bOGRAPISpyEnabled )
1227         OGRAPISpy_L_SetSpatialFilterRect(hLayer, dfMinX, dfMinY, dfMaxX, dfMaxY);
1228 #endif
1229 
1230     OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect( dfMinX, dfMinY,
1231                                                  dfMaxX, dfMaxY );
1232 }
1233 
1234 /************************************************************************/
1235 /*                    OGR_L_SetSpatialFilterRectEx()                    */
1236 /************************************************************************/
1237 
OGR_L_SetSpatialFilterRectEx(OGRLayerH hLayer,int iGeomField,double dfMinX,double dfMinY,double dfMaxX,double dfMaxY)1238 void OGR_L_SetSpatialFilterRectEx( OGRLayerH hLayer,
1239                                    int iGeomField,
1240                                    double dfMinX, double dfMinY,
1241                                    double dfMaxX, double dfMaxY )
1242 
1243 {
1244     VALIDATE_POINTER0( hLayer, "OGR_L_SetSpatialFilterRectEx" );
1245 
1246 #ifdef OGRAPISPY_ENABLED
1247     if( bOGRAPISpyEnabled )
1248         OGRAPISpy_L_SetSpatialFilterRectEx(hLayer, iGeomField, dfMinX, dfMinY, dfMaxX, dfMaxY);
1249 #endif
1250 
1251     OGRLayer::FromHandle(hLayer)->SetSpatialFilterRect( iGeomField,
1252                                                  dfMinX, dfMinY,
1253                                                  dfMaxX, dfMaxY );
1254 }
1255 
1256 /************************************************************************/
1257 /*                           InstallFilter()                            */
1258 /*                                                                      */
1259 /*      This method is only intended to be used from within             */
1260 /*      drivers, normally from the SetSpatialFilter() method.           */
1261 /*      It installs a filter, and also tests it to see if it is         */
1262 /*      rectangular.  If so, it this is kept track of alongside the     */
1263 /*      filter geometry itself so we can do cheaper comparisons in      */
1264 /*      the FilterGeometry() call.                                      */
1265 /*                                                                      */
1266 /*      Returns TRUE if the newly installed filter differs in some      */
1267 /*      way from the current one.                                       */
1268 /************************************************************************/
1269 
1270 //! @cond Doxygen_Suppress
InstallFilter(OGRGeometry * poFilter)1271 int OGRLayer::InstallFilter( OGRGeometry * poFilter )
1272 
1273 {
1274     if( m_poFilterGeom == poFilter )
1275         return FALSE;
1276 
1277 /* -------------------------------------------------------------------- */
1278 /*      Replace the existing filter.                                    */
1279 /* -------------------------------------------------------------------- */
1280     if( m_poFilterGeom != nullptr )
1281     {
1282         delete m_poFilterGeom;
1283         m_poFilterGeom = nullptr;
1284     }
1285 
1286     if( m_pPreparedFilterGeom != nullptr )
1287     {
1288         OGRDestroyPreparedGeometry(m_pPreparedFilterGeom);
1289         m_pPreparedFilterGeom = nullptr;
1290     }
1291 
1292     if( poFilter != nullptr )
1293         m_poFilterGeom = poFilter->clone();
1294 
1295     m_bFilterIsEnvelope = FALSE;
1296 
1297     if( m_poFilterGeom == nullptr )
1298         return TRUE;
1299 
1300     if( m_poFilterGeom != nullptr )
1301         m_poFilterGeom->getEnvelope( &m_sFilterEnvelope );
1302 
1303     /* Compile geometry filter as a prepared geometry */
1304     m_pPreparedFilterGeom = OGRCreatePreparedGeometry(OGRGeometry::ToHandle(m_poFilterGeom));
1305 
1306 /* -------------------------------------------------------------------- */
1307 /*      Now try to determine if the filter is really a rectangle.       */
1308 /* -------------------------------------------------------------------- */
1309     if( wkbFlatten(m_poFilterGeom->getGeometryType()) != wkbPolygon )
1310         return TRUE;
1311 
1312     OGRPolygon *poPoly = m_poFilterGeom->toPolygon();
1313 
1314     if( poPoly->getNumInteriorRings() != 0 )
1315         return TRUE;
1316 
1317     OGRLinearRing *poRing = poPoly->getExteriorRing();
1318     if (poRing == nullptr)
1319         return TRUE;
1320 
1321     if( poRing->getNumPoints() > 5 || poRing->getNumPoints() < 4 )
1322         return TRUE;
1323 
1324     // If the ring has 5 points, the last should be the first.
1325     if( poRing->getNumPoints() == 5
1326         && ( poRing->getX(0) != poRing->getX(4)
1327              || poRing->getY(0) != poRing->getY(4) ) )
1328         return TRUE;
1329 
1330     // Polygon with first segment in "y" direction.
1331     if( poRing->getX(0) == poRing->getX(1)
1332         && poRing->getY(1) == poRing->getY(2)
1333         && poRing->getX(2) == poRing->getX(3)
1334         && poRing->getY(3) == poRing->getY(0) )
1335         m_bFilterIsEnvelope = TRUE;
1336 
1337     // Polygon with first segment in "x" direction.
1338     if( poRing->getY(0) == poRing->getY(1)
1339         && poRing->getX(1) == poRing->getX(2)
1340         && poRing->getY(2) == poRing->getY(3)
1341         && poRing->getX(3) == poRing->getX(0) )
1342         m_bFilterIsEnvelope = TRUE;
1343 
1344     return TRUE;
1345 }
1346 //! @endcond
1347 
1348 /************************************************************************/
1349 /*                           FilterGeometry()                           */
1350 /*                                                                      */
1351 /*      Compare the passed in geometry to the currently installed       */
1352 /*      filter.  Optimize for case where filter is just an              */
1353 /*      envelope.                                                       */
1354 /************************************************************************/
1355 
1356 //! @cond Doxygen_Suppress
FilterGeometry(OGRGeometry * poGeometry)1357 int OGRLayer::FilterGeometry( OGRGeometry *poGeometry )
1358 
1359 {
1360 /* -------------------------------------------------------------------- */
1361 /*      In trivial cases of new filter or target geometry, we accept    */
1362 /*      an intersection.  No geometry is taken to mean "the whole       */
1363 /*      world".                                                         */
1364 /* -------------------------------------------------------------------- */
1365     if( m_poFilterGeom == nullptr )
1366         return TRUE;
1367 
1368     if( poGeometry == nullptr || poGeometry->IsEmpty() )
1369         return FALSE;
1370 
1371 /* -------------------------------------------------------------------- */
1372 /*      Compute the target geometry envelope, and if there is no        */
1373 /*      intersection between the envelopes we are sure not to have      */
1374 /*      any intersection.                                               */
1375 /* -------------------------------------------------------------------- */
1376     OGREnvelope sGeomEnv;
1377 
1378     poGeometry->getEnvelope( &sGeomEnv );
1379 
1380     if( sGeomEnv.MaxX < m_sFilterEnvelope.MinX
1381         || sGeomEnv.MaxY < m_sFilterEnvelope.MinY
1382         || m_sFilterEnvelope.MaxX < sGeomEnv.MinX
1383         || m_sFilterEnvelope.MaxY < sGeomEnv.MinY )
1384         return FALSE;
1385 
1386 /* -------------------------------------------------------------------- */
1387 /*      If the filter geometry is its own envelope and if the           */
1388 /*      envelope of the geometry is inside the filter geometry,         */
1389 /*      the geometry itself is inside the filter geometry               */
1390 /* -------------------------------------------------------------------- */
1391     if( m_bFilterIsEnvelope &&
1392         sGeomEnv.MinX >= m_sFilterEnvelope.MinX &&
1393         sGeomEnv.MinY >= m_sFilterEnvelope.MinY &&
1394         sGeomEnv.MaxX <= m_sFilterEnvelope.MaxX &&
1395         sGeomEnv.MaxY <= m_sFilterEnvelope.MaxY)
1396     {
1397         return TRUE;
1398     }
1399     else
1400     {
1401 /* -------------------------------------------------------------------- */
1402 /*      If the filter geometry is its own envelope and if the           */
1403 /*      the geometry (line, or polygon without hole) h has at least one */
1404 /*      point inside the filter geometry, the geometry itself is inside */
1405 /*      the filter geometry.                                            */
1406 /* -------------------------------------------------------------------- */
1407         if( m_bFilterIsEnvelope )
1408         {
1409             OGRLineString* poLS = nullptr;
1410 
1411             switch( wkbFlatten(poGeometry->getGeometryType()) )
1412             {
1413                 case wkbPolygon:
1414                 {
1415                     OGRPolygon* poPoly = poGeometry->toPolygon();
1416                     OGRLinearRing* poRing = poPoly->getExteriorRing();
1417                     if (poRing != nullptr && poPoly->getNumInteriorRings() == 0)
1418                     {
1419                         poLS = poRing;
1420                     }
1421                     break;
1422                 }
1423 
1424                 case wkbLineString:
1425                     poLS = poGeometry->toLineString();
1426                     break;
1427 
1428                 default:
1429                     break;
1430             }
1431 
1432             if( poLS != nullptr )
1433             {
1434                 int nNumPoints = poLS->getNumPoints();
1435                 for(int i = 0; i < nNumPoints; i++)
1436                 {
1437                     double x = poLS->getX(i);
1438                     double y = poLS->getY(i);
1439                     if (x >= m_sFilterEnvelope.MinX &&
1440                         y >= m_sFilterEnvelope.MinY &&
1441                         x <= m_sFilterEnvelope.MaxX &&
1442                         y <= m_sFilterEnvelope.MaxY)
1443                     {
1444                         return TRUE;
1445                     }
1446                 }
1447             }
1448         }
1449 
1450 /* -------------------------------------------------------------------- */
1451 /*      Fallback to full intersect test (using GEOS) if we still        */
1452 /*      don't know for sure.                                            */
1453 /* -------------------------------------------------------------------- */
1454         if( OGRGeometryFactory::haveGEOS() )
1455         {
1456             //CPLDebug("OGRLayer", "GEOS intersection");
1457             if( m_pPreparedFilterGeom != nullptr )
1458                 return OGRPreparedGeometryIntersects(m_pPreparedFilterGeom,
1459                                                      OGRGeometry::ToHandle(poGeometry));
1460             else
1461                 return m_poFilterGeom->Intersects( poGeometry );
1462         }
1463         else
1464             return TRUE;
1465     }
1466 }
1467 //! @endcond
1468 
1469 /************************************************************************/
1470 /*                         OGR_L_ResetReading()                         */
1471 /************************************************************************/
1472 
OGR_L_ResetReading(OGRLayerH hLayer)1473 void OGR_L_ResetReading( OGRLayerH hLayer )
1474 
1475 {
1476     VALIDATE_POINTER0( hLayer, "OGR_L_ResetReading" );
1477 
1478 #ifdef OGRAPISPY_ENABLED
1479     if( bOGRAPISpyEnabled )
1480         OGRAPISpy_L_ResetReading(hLayer);
1481 #endif
1482 
1483     OGRLayer::FromHandle(hLayer)->ResetReading();
1484 }
1485 
1486 /************************************************************************/
1487 /*                       InitializeIndexSupport()                       */
1488 /*                                                                      */
1489 /*      This is only intended to be called by driver layer              */
1490 /*      implementations but we don't make it protected so that the      */
1491 /*      datasources can do it too if that is more appropriate.          */
1492 /************************************************************************/
1493 
1494 //! @cond Doxygen_Suppress
InitializeIndexSupport(const char * pszFilename)1495 OGRErr OGRLayer::InitializeIndexSupport( const char *pszFilename )
1496 
1497 {
1498     OGRErr eErr;
1499 
1500     if (m_poAttrIndex != nullptr)
1501         return OGRERR_NONE;
1502 
1503     m_poAttrIndex = OGRCreateDefaultLayerIndex();
1504 
1505     eErr = m_poAttrIndex->Initialize( pszFilename, this );
1506     if( eErr != OGRERR_NONE )
1507     {
1508         delete m_poAttrIndex;
1509         m_poAttrIndex = nullptr;
1510     }
1511 
1512     return eErr;
1513 }
1514 //! @endcond
1515 
1516 /************************************************************************/
1517 /*                             SyncToDisk()                             */
1518 /************************************************************************/
1519 
SyncToDisk()1520 OGRErr OGRLayer::SyncToDisk()
1521 
1522 {
1523     return OGRERR_NONE;
1524 }
1525 
1526 /************************************************************************/
1527 /*                          OGR_L_SyncToDisk()                          */
1528 /************************************************************************/
1529 
OGR_L_SyncToDisk(OGRLayerH hLayer)1530 OGRErr OGR_L_SyncToDisk( OGRLayerH hLayer )
1531 
1532 {
1533     VALIDATE_POINTER1( hLayer, "OGR_L_SyncToDisk", OGRERR_INVALID_HANDLE );
1534 
1535 #ifdef OGRAPISPY_ENABLED
1536     if( bOGRAPISpyEnabled )
1537         OGRAPISpy_L_SyncToDisk(hLayer);
1538 #endif
1539 
1540     return OGRLayer::FromHandle(hLayer)->SyncToDisk();
1541 }
1542 
1543 /************************************************************************/
1544 /*                           DeleteFeature()                            */
1545 /************************************************************************/
1546 
DeleteFeature(CPL_UNUSED GIntBig nFID)1547 OGRErr OGRLayer::DeleteFeature( CPL_UNUSED GIntBig nFID )
1548 {
1549     return OGRERR_UNSUPPORTED_OPERATION;
1550 }
1551 
1552 /************************************************************************/
1553 /*                        OGR_L_DeleteFeature()                         */
1554 /************************************************************************/
1555 
OGR_L_DeleteFeature(OGRLayerH hLayer,GIntBig nFID)1556 OGRErr OGR_L_DeleteFeature( OGRLayerH hLayer, GIntBig nFID )
1557 
1558 {
1559     VALIDATE_POINTER1( hLayer, "OGR_L_DeleteFeature", OGRERR_INVALID_HANDLE );
1560 
1561 #ifdef OGRAPISPY_ENABLED
1562     if( bOGRAPISpyEnabled )
1563         OGRAPISpy_L_DeleteFeature(hLayer, nFID);
1564 #endif
1565 
1566     return OGRLayer::FromHandle(hLayer)->DeleteFeature( nFID );
1567 }
1568 
1569 /************************************************************************/
1570 /*                          GetFeaturesRead()                           */
1571 /************************************************************************/
1572 
1573 //! @cond Doxygen_Suppress
GetFeaturesRead()1574 GIntBig OGRLayer::GetFeaturesRead()
1575 
1576 {
1577     return m_nFeaturesRead;
1578 }
1579 //! @endcond
1580 
1581 /************************************************************************/
1582 /*                       OGR_L_GetFeaturesRead()                        */
1583 /************************************************************************/
1584 
OGR_L_GetFeaturesRead(OGRLayerH hLayer)1585 GIntBig OGR_L_GetFeaturesRead( OGRLayerH hLayer )
1586 
1587 {
1588     VALIDATE_POINTER1( hLayer, "OGR_L_GetFeaturesRead", 0 );
1589 
1590     return OGRLayer::FromHandle(hLayer)->GetFeaturesRead();
1591 }
1592 
1593 /************************************************************************/
1594 /*                             GetFIDColumn                             */
1595 /************************************************************************/
1596 
GetFIDColumn()1597 const char *OGRLayer::GetFIDColumn()
1598 
1599 {
1600     return "";
1601 }
1602 
1603 /************************************************************************/
1604 /*                         OGR_L_GetFIDColumn()                         */
1605 /************************************************************************/
1606 
OGR_L_GetFIDColumn(OGRLayerH hLayer)1607 const char *OGR_L_GetFIDColumn( OGRLayerH hLayer )
1608 
1609 {
1610     VALIDATE_POINTER1( hLayer, "OGR_L_GetFIDColumn", nullptr );
1611 
1612 #ifdef OGRAPISPY_ENABLED
1613     if( bOGRAPISpyEnabled )
1614         OGRAPISpy_L_GetFIDColumn(hLayer);
1615 #endif
1616 
1617     return OGRLayer::FromHandle(hLayer)->GetFIDColumn();
1618 }
1619 
1620 /************************************************************************/
1621 /*                         GetGeometryColumn()                          */
1622 /************************************************************************/
1623 
GetGeometryColumn()1624 const char *OGRLayer::GetGeometryColumn()
1625 
1626 {
1627     if( GetLayerDefn()->GetGeomFieldCount() > 0 )
1628         return GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef();
1629     else
1630         return "";
1631 }
1632 
1633 /************************************************************************/
1634 /*                      OGR_L_GetGeometryColumn()                       */
1635 /************************************************************************/
1636 
OGR_L_GetGeometryColumn(OGRLayerH hLayer)1637 const char *OGR_L_GetGeometryColumn( OGRLayerH hLayer )
1638 
1639 {
1640     VALIDATE_POINTER1( hLayer, "OGR_L_GetGeometryColumn", nullptr );
1641 
1642 #ifdef OGRAPISPY_ENABLED
1643     if( bOGRAPISpyEnabled )
1644         OGRAPISpy_L_GetGeometryColumn(hLayer);
1645 #endif
1646 
1647     return OGRLayer::FromHandle(hLayer)->GetGeometryColumn();
1648 }
1649 
1650 /************************************************************************/
1651 /*                            GetStyleTable()                           */
1652 /************************************************************************/
1653 
GetStyleTable()1654 OGRStyleTable *OGRLayer::GetStyleTable()
1655 {
1656     return m_poStyleTable;
1657 }
1658 
1659 /************************************************************************/
1660 /*                         SetStyleTableDirectly()                      */
1661 /************************************************************************/
1662 
SetStyleTableDirectly(OGRStyleTable * poStyleTable)1663 void OGRLayer::SetStyleTableDirectly( OGRStyleTable *poStyleTable )
1664 {
1665     if ( m_poStyleTable )
1666         delete m_poStyleTable;
1667     m_poStyleTable = poStyleTable;
1668 }
1669 
1670 /************************************************************************/
1671 /*                            SetStyleTable()                           */
1672 /************************************************************************/
1673 
SetStyleTable(OGRStyleTable * poStyleTable)1674 void OGRLayer::SetStyleTable(OGRStyleTable *poStyleTable)
1675 {
1676     if ( m_poStyleTable )
1677         delete m_poStyleTable;
1678     if ( poStyleTable )
1679         m_poStyleTable = poStyleTable->Clone();
1680 }
1681 
1682 /************************************************************************/
1683 /*                         OGR_L_GetStyleTable()                        */
1684 /************************************************************************/
1685 
OGR_L_GetStyleTable(OGRLayerH hLayer)1686 OGRStyleTableH OGR_L_GetStyleTable( OGRLayerH hLayer )
1687 
1688 {
1689     VALIDATE_POINTER1( hLayer, "OGR_L_GetStyleTable", nullptr );
1690 
1691     return reinterpret_cast<OGRStyleTableH>(
1692         OGRLayer::FromHandle(hLayer)->GetStyleTable( ));
1693 }
1694 
1695 /************************************************************************/
1696 /*                         OGR_L_SetStyleTableDirectly()                */
1697 /************************************************************************/
1698 
OGR_L_SetStyleTableDirectly(OGRLayerH hLayer,OGRStyleTableH hStyleTable)1699 void OGR_L_SetStyleTableDirectly( OGRLayerH hLayer,
1700                                   OGRStyleTableH hStyleTable )
1701 
1702 {
1703     VALIDATE_POINTER0( hLayer, "OGR_L_SetStyleTableDirectly" );
1704 
1705     OGRLayer::FromHandle(hLayer)->SetStyleTableDirectly(
1706         reinterpret_cast<OGRStyleTable *>(hStyleTable) );
1707 }
1708 
1709 /************************************************************************/
1710 /*                         OGR_L_SetStyleTable()                        */
1711 /************************************************************************/
1712 
OGR_L_SetStyleTable(OGRLayerH hLayer,OGRStyleTableH hStyleTable)1713 void OGR_L_SetStyleTable( OGRLayerH hLayer,
1714                           OGRStyleTableH hStyleTable )
1715 
1716 {
1717     VALIDATE_POINTER0( hLayer, "OGR_L_SetStyleTable" );
1718     VALIDATE_POINTER0( hStyleTable, "OGR_L_SetStyleTable" );
1719 
1720     OGRLayer::FromHandle(hLayer)->SetStyleTable(
1721         reinterpret_cast<OGRStyleTable *>(hStyleTable) );
1722 }
1723 
1724 /************************************************************************/
1725 /*                               GetName()                              */
1726 /************************************************************************/
1727 
GetName()1728 const char *OGRLayer::GetName()
1729 
1730 {
1731     return GetLayerDefn()->GetName();
1732 }
1733 
1734 /************************************************************************/
1735 /*                           OGR_L_GetName()                            */
1736 /************************************************************************/
1737 
OGR_L_GetName(OGRLayerH hLayer)1738 const char* OGR_L_GetName( OGRLayerH hLayer )
1739 
1740 {
1741     VALIDATE_POINTER1( hLayer, "OGR_L_GetName", "" );
1742 
1743 #ifdef OGRAPISPY_ENABLED
1744     if( bOGRAPISpyEnabled )
1745         OGRAPISpy_L_GetName(hLayer);
1746 #endif
1747 
1748     return OGRLayer::FromHandle(hLayer)->GetName();
1749 }
1750 
1751 /************************************************************************/
1752 /*                            GetGeomType()                             */
1753 /************************************************************************/
1754 
GetGeomType()1755 OGRwkbGeometryType OGRLayer::GetGeomType()
1756 {
1757     OGRFeatureDefn* poLayerDefn = GetLayerDefn();
1758     if( poLayerDefn == nullptr )
1759     {
1760         CPLDebug("OGR", "GetLayerType() returns NULL !");
1761         return wkbUnknown;
1762     }
1763     return poLayerDefn->GetGeomType();
1764 }
1765 
1766 /************************************************************************/
1767 /*                         OGR_L_GetGeomType()                          */
1768 /************************************************************************/
1769 
OGR_L_GetGeomType(OGRLayerH hLayer)1770 OGRwkbGeometryType OGR_L_GetGeomType( OGRLayerH hLayer )
1771 
1772 {
1773     VALIDATE_POINTER1( hLayer, "OGR_L_GetGeomType", wkbUnknown );
1774 
1775 #ifdef OGRAPISPY_ENABLED
1776     if( bOGRAPISpyEnabled )
1777         OGRAPISpy_L_GetGeomType(hLayer);
1778 #endif
1779 
1780     OGRwkbGeometryType eType = OGRLayer::FromHandle(hLayer)->GetGeomType();
1781     if( OGR_GT_IsNonLinear(eType) && !OGRGetNonLinearGeometriesEnabledFlag() )
1782     {
1783         eType = OGR_GT_GetLinear(eType);
1784     }
1785     return eType;
1786 }
1787 
1788 /************************************************************************/
1789 /*                          SetIgnoredFields()                          */
1790 /************************************************************************/
1791 
SetIgnoredFields(const char ** papszFields)1792 OGRErr OGRLayer::SetIgnoredFields( const char **papszFields )
1793 {
1794     OGRFeatureDefn *poDefn = GetLayerDefn();
1795 
1796     // first set everything as *not* ignored
1797     for( int iField = 0; iField < poDefn->GetFieldCount(); iField++ )
1798     {
1799         poDefn->GetFieldDefn(iField)->SetIgnored( FALSE );
1800     }
1801     for( int iField = 0; iField < poDefn->GetGeomFieldCount(); iField++ )
1802     {
1803         poDefn->GetGeomFieldDefn(iField)->SetIgnored( FALSE );
1804     }
1805     poDefn->SetStyleIgnored( FALSE );
1806 
1807     if ( papszFields == nullptr )
1808         return OGRERR_NONE;
1809 
1810     // ignore some fields
1811     while ( *papszFields )
1812     {
1813         const char* pszFieldName = *papszFields;
1814         // check special fields
1815         if ( EQUAL(pszFieldName, "OGR_GEOMETRY") )
1816             poDefn->SetGeometryIgnored( TRUE );
1817         else if ( EQUAL(pszFieldName, "OGR_STYLE") )
1818             poDefn->SetStyleIgnored( TRUE );
1819         else
1820         {
1821             // check ordinary fields
1822             int iField = poDefn->GetFieldIndex(pszFieldName);
1823             if ( iField == -1 )
1824             {
1825                 // check geometry field
1826                 iField = poDefn->GetGeomFieldIndex(pszFieldName);
1827                 if ( iField == -1 )
1828                 {
1829                     return OGRERR_FAILURE;
1830                 }
1831                 else
1832                     poDefn->GetGeomFieldDefn(iField)->SetIgnored( TRUE );
1833             }
1834             else
1835                 poDefn->GetFieldDefn(iField)->SetIgnored( TRUE );
1836         }
1837         papszFields++;
1838     }
1839 
1840     return OGRERR_NONE;
1841 }
1842 
1843 /************************************************************************/
1844 /*                       OGR_L_SetIgnoredFields()                       */
1845 /************************************************************************/
1846 
OGR_L_SetIgnoredFields(OGRLayerH hLayer,const char ** papszFields)1847 OGRErr OGR_L_SetIgnoredFields( OGRLayerH hLayer, const char **papszFields )
1848 
1849 {
1850     VALIDATE_POINTER1( hLayer, "OGR_L_SetIgnoredFields", OGRERR_INVALID_HANDLE );
1851 
1852 #ifdef OGRAPISPY_ENABLED
1853     if( bOGRAPISpyEnabled )
1854         OGRAPISpy_L_SetIgnoredFields(hLayer, papszFields);
1855 #endif
1856 
1857     return OGRLayer::FromHandle(hLayer)->SetIgnoredFields( papszFields );
1858 }
1859 
1860 /************************************************************************/
1861 /*         helper functions for layer overlay methods                   */
1862 /************************************************************************/
1863 
1864 static
clone_spatial_filter(OGRLayer * pLayer,OGRGeometry ** ppGeometry)1865 OGRErr clone_spatial_filter(OGRLayer *pLayer, OGRGeometry **ppGeometry)
1866 {
1867     OGRErr ret = OGRERR_NONE;
1868     OGRGeometry *g = pLayer->GetSpatialFilter();
1869     *ppGeometry = g ? g->clone() : nullptr;
1870     return ret;
1871 }
1872 
1873 static
create_field_map(OGRFeatureDefn * poDefn,int ** map)1874 OGRErr create_field_map(OGRFeatureDefn *poDefn, int **map)
1875 {
1876     OGRErr ret = OGRERR_NONE;
1877     int n = poDefn->GetFieldCount();
1878     if (n > 0) {
1879         *map = static_cast<int*>(VSI_MALLOC_VERBOSE(sizeof(int) * n));
1880         if (!(*map)) return OGRERR_NOT_ENOUGH_MEMORY;
1881         for(int i=0;i<n;i++)
1882             (*map)[i] = -1;
1883     }
1884     return ret;
1885 }
1886 
1887 static
set_result_schema(OGRLayer * pLayerResult,OGRFeatureDefn * poDefnInput,OGRFeatureDefn * poDefnMethod,int * mapInput,int * mapMethod,bool combined,const char * const * papszOptions)1888 OGRErr set_result_schema(OGRLayer *pLayerResult,
1889                          OGRFeatureDefn *poDefnInput,
1890                          OGRFeatureDefn *poDefnMethod,
1891                          int *mapInput,
1892                          int *mapMethod,
1893                          bool combined,
1894                          const char* const* papszOptions)
1895 {
1896     OGRErr ret = OGRERR_NONE;
1897     OGRFeatureDefn *poDefnResult = pLayerResult->GetLayerDefn();
1898     const char* pszInputPrefix = CSLFetchNameValue(papszOptions, "INPUT_PREFIX");
1899     const char* pszMethodPrefix = CSLFetchNameValue(papszOptions, "METHOD_PREFIX");
1900     int bSkipFailures = CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
1901     if (poDefnResult->GetFieldCount() > 0) {
1902         // the user has defined the schema of the output layer
1903         if( mapInput )
1904         {
1905             for( int iField = 0; iField < poDefnInput->GetFieldCount(); iField++ ) {
1906                 CPLString osName(poDefnInput->GetFieldDefn(iField)->GetNameRef());
1907                 if( pszInputPrefix != nullptr )
1908                     osName = pszInputPrefix + osName;
1909                 mapInput[iField] = poDefnResult->GetFieldIndex(osName);
1910             }
1911         }
1912         if (!mapMethod) return ret;
1913         // cppcheck-suppress nullPointer
1914         for( int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++ ) {
1915             // cppcheck-suppress nullPointer
1916             CPLString osName(poDefnMethod->GetFieldDefn(iField)->GetNameRef());
1917             if( pszMethodPrefix != nullptr )
1918                 osName = pszMethodPrefix + osName;
1919             mapMethod[iField] = poDefnResult->GetFieldIndex(osName);
1920         }
1921     } else {
1922         // use schema from the input layer or from input and method layers
1923         int nFieldsInput = poDefnInput->GetFieldCount();
1924         for( int iField = 0; iField < nFieldsInput; iField++ ) {
1925             OGRFieldDefn oFieldDefn(poDefnInput->GetFieldDefn(iField));
1926             if( pszInputPrefix != nullptr )
1927                 oFieldDefn.SetName(CPLSPrintf("%s%s", pszInputPrefix, oFieldDefn.GetNameRef()));
1928             ret = pLayerResult->CreateField(&oFieldDefn);
1929             if (ret != OGRERR_NONE) {
1930                 if (!bSkipFailures)
1931                     return ret;
1932                 else {
1933                     CPLErrorReset();
1934                     ret = OGRERR_NONE;
1935                 }
1936             }
1937             if( mapInput )
1938                 mapInput[iField] = iField;
1939         }
1940         if (!combined) return ret;
1941         if (!mapMethod) return ret;
1942         if (!poDefnMethod) return ret;
1943         for( int iField = 0; iField < poDefnMethod->GetFieldCount(); iField++ ) {
1944             OGRFieldDefn oFieldDefn(poDefnMethod->GetFieldDefn(iField));
1945             if( pszMethodPrefix != nullptr )
1946                 oFieldDefn.SetName(CPLSPrintf("%s%s", pszMethodPrefix, oFieldDefn.GetNameRef()));
1947             ret = pLayerResult->CreateField(&oFieldDefn);
1948             if (ret != OGRERR_NONE) {
1949                 if (!bSkipFailures)
1950                     return ret;
1951                 else {
1952                     CPLErrorReset();
1953                     ret = OGRERR_NONE;
1954                 }
1955             }
1956             mapMethod[iField] = nFieldsInput+iField;
1957         }
1958     }
1959     return ret;
1960 }
1961 
1962 static
set_filter_from(OGRLayer * pLayer,OGRGeometry * pGeometryExistingFilter,OGRFeature * pFeature)1963 OGRGeometry *set_filter_from(OGRLayer *pLayer, OGRGeometry *pGeometryExistingFilter, OGRFeature *pFeature)
1964 {
1965     OGRGeometry *geom = pFeature->GetGeometryRef();
1966     if (!geom) return nullptr;
1967     if (pGeometryExistingFilter) {
1968         if (!geom->Intersects(pGeometryExistingFilter)) return nullptr;
1969         OGRGeometry *intersection = geom->Intersection(pGeometryExistingFilter);
1970         if (intersection) {
1971             pLayer->SetSpatialFilter(intersection);
1972             delete intersection;
1973         } else
1974             return nullptr;
1975     } else {
1976         pLayer->SetSpatialFilter(geom);
1977     }
1978     return geom;
1979 }
1980 
promote_to_multi(OGRGeometry * poGeom)1981 static OGRGeometry* promote_to_multi(OGRGeometry* poGeom)
1982 {
1983     OGRwkbGeometryType eType = wkbFlatten(poGeom->getGeometryType());
1984     if( eType == wkbPolygon )
1985         return OGRGeometryFactory::forceToMultiPolygon(poGeom);
1986     else if( eType == wkbLineString )
1987         return OGRGeometryFactory::forceToMultiLineString(poGeom);
1988     else
1989         return poGeom;
1990 }
1991 
1992 /************************************************************************/
1993 /*                          Intersection()                              */
1994 /************************************************************************/
1995 /**
1996  * \brief Intersection of two layers.
1997  *
1998  * The result layer contains features whose geometries represent areas
1999  * that are common between features in the input layer and in the
2000  * method layer. The features in the result layer have attributes from
2001  * both input and method layers. The schema of the result layer can be
2002  * set by the user or, if it is empty, is initialized to contain all
2003  * fields in the input and method layers.
2004  *
2005  * \note If the schema of the result is set by user and contains
2006  * fields that have the same name as a field in input and in method
2007  * layer, then the attribute in the result feature will get the value
2008  * from the feature of the method layer.
2009  *
2010  * \note For best performance use the minimum amount of features in
2011  * the method layer and copy it into a memory layer.
2012  *
2013  * \note This method relies on GEOS support. Do not use unless the
2014  * GEOS support is compiled in.
2015  *
2016  * The recognized list of options is:
2017  * <ul>
2018  * <li>SKIP_FAILURES=YES/NO. Set to YES to go on, even when a
2019  *     feature could not be inserted or a GEOS call failed.
2020  * <li>PROMOTE_TO_MULTI=YES/NO. Set to YES to convert Polygons
2021  *     into MultiPolygons, or LineStrings to MultiLineStrings.
2022  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
2023  *     will be created from the fields of the input layer.
2024  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
2025  *     will be created from the fields of the method layer.
2026  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
2027  *     geometries to pretest intersection of features of method layer
2028  *     with features of this layer.
2029  * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
2030  *     containment of features of method layer within the features of
2031  *     this layer. This will speed up the method significantly in some
2032  *     cases. Requires that the prepared geometries are in effect.
2033  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
2034  *     result features with lower dimension geometry that would
2035  *     otherwise be added to the result layer. The default is to add
2036  *     but only if the result layer has an unknown geometry type.
2037  * </ul>
2038  *
2039  * This method is the same as the C function OGR_L_Intersection().
2040  *
2041  * @param pLayerMethod the method layer. Should not be NULL.
2042  *
2043  * @param pLayerResult the layer where the features resulting from the
2044  * operation are inserted. Should not be NULL. See above the note
2045  * about the schema.
2046  *
2047  * @param papszOptions NULL terminated list of options (may be NULL).
2048  *
2049  * @param pfnProgress a GDALProgressFunc() compatible callback function for
2050  * reporting progress or NULL.
2051  *
2052  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
2053  *
2054  * @return an error code if there was an error or the execution was
2055  * interrupted, OGRERR_NONE otherwise.
2056  *
2057  * @note The first geometry field is always used.
2058  *
2059  * @since OGR 1.10
2060  */
2061 
Intersection(OGRLayer * pLayerMethod,OGRLayer * pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)2062 OGRErr OGRLayer::Intersection( OGRLayer *pLayerMethod,
2063                                OGRLayer *pLayerResult,
2064                                char** papszOptions,
2065                                GDALProgressFunc pfnProgress,
2066                                void * pProgressArg )
2067 {
2068     OGRErr ret = OGRERR_NONE;
2069     OGRFeatureDefn *poDefnInput = GetLayerDefn();
2070     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
2071     OGRFeatureDefn *poDefnResult = nullptr;
2072     OGRGeometry *pGeometryMethodFilter = nullptr;
2073     int *mapInput = nullptr;
2074     int *mapMethod = nullptr;
2075     OGREnvelope sEnvelopeMethod;
2076     GBool bEnvelopeSet;
2077     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
2078     double progress_counter = 0;
2079     double progress_ticker = 0;
2080     int bSkipFailures = CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
2081     int bPromoteToMulti = CPLTestBool(CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
2082     int bUsePreparedGeometries = CPLTestBool(CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
2083     if (bUsePreparedGeometries) bUsePreparedGeometries = OGRHasPreparedGeometrySupport();
2084     int bPretestContainment = CPLTestBool(CSLFetchNameValueDef(papszOptions, "PRETEST_CONTAINMENT", "NO"));
2085     int bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
2086 
2087     // check for GEOS
2088     if (!OGRGeometryFactory::haveGEOS()) {
2089         return OGRERR_UNSUPPORTED_OPERATION;
2090     }
2091 
2092     // get resources
2093     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
2094     if (ret != OGRERR_NONE) goto done;
2095     ret = create_field_map(poDefnInput, &mapInput);
2096     if (ret != OGRERR_NONE) goto done;
2097     ret = create_field_map(poDefnMethod, &mapMethod);
2098     if (ret != OGRERR_NONE) goto done;
2099     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput, mapMethod, true, papszOptions);
2100     if (ret != OGRERR_NONE) goto done;
2101     poDefnResult = pLayerResult->GetLayerDefn();
2102     bEnvelopeSet = pLayerMethod->GetExtent(&sEnvelopeMethod, 1) == OGRERR_NONE;
2103     if (bKeepLowerDimGeom) {
2104         // require that the result layer is of geom type unknown
2105         if (pLayerResult->GetGeomType() != wkbUnknown) {
2106             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO since the result layer does not allow it.");
2107             bKeepLowerDimGeom = FALSE;
2108         }
2109     }
2110 
2111     for( auto&& x: this ) {
2112 
2113         if (pfnProgress) {
2114             double p = progress_counter/progress_max;
2115             if (p > progress_ticker) {
2116                 if (!pfnProgress(p, "", pProgressArg)) {
2117                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
2118                     ret = OGRERR_FAILURE;
2119                     goto done;
2120                 }
2121             }
2122             progress_counter += 1.0;
2123         }
2124 
2125         // is it worth to proceed?
2126         if (bEnvelopeSet) {
2127             OGRGeometry *x_geom = x->GetGeometryRef();
2128             if (x_geom) {
2129                 OGREnvelope x_env;
2130                 x_geom->getEnvelope(&x_env);
2131                 if (x_env.MaxX < sEnvelopeMethod.MinX
2132                     || x_env.MaxY < sEnvelopeMethod.MinY
2133                     || sEnvelopeMethod.MaxX < x_env.MinX
2134                     || sEnvelopeMethod.MaxY < x_env.MinY) {
2135                     continue;
2136                 }
2137             } else {
2138                 continue;
2139             }
2140         }
2141 
2142         // set up the filter for method layer
2143         CPLErrorReset();
2144         OGRGeometry *x_geom = set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
2145         if (CPLGetLastErrorType() != CE_None) {
2146             if (!bSkipFailures) {
2147                 ret = OGRERR_FAILURE;
2148                 goto done;
2149             } else {
2150                 CPLErrorReset();
2151                 ret = OGRERR_NONE;
2152             }
2153         }
2154         if (!x_geom) {
2155             continue;
2156         }
2157 
2158         OGRPreparedGeometryUniquePtr x_prepared_geom;
2159         if (bUsePreparedGeometries) {
2160             x_prepared_geom.reset(OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
2161             if (!x_prepared_geom) {
2162                 goto done;
2163             }
2164         }
2165 
2166         for( auto&& y: pLayerMethod ) {
2167             OGRGeometry *y_geom = y->GetGeometryRef();
2168             if (!y_geom) continue;
2169             OGRGeometryUniquePtr z_geom;
2170 
2171             if (x_prepared_geom) {
2172                 CPLErrorReset();
2173                 ret = OGRERR_NONE;
2174                 if (bPretestContainment && OGRPreparedGeometryContains(x_prepared_geom.get(), OGRGeometry::ToHandle(y_geom)))
2175                 {
2176                     if (CPLGetLastErrorType() == CE_None)
2177                         z_geom.reset(y_geom->clone());
2178                 }
2179                 else if (!(OGRPreparedGeometryIntersects(x_prepared_geom.get(), OGRGeometry::ToHandle(y_geom))))
2180                 {
2181                     if (CPLGetLastErrorType() == CE_None) {
2182                         continue;
2183                     }
2184                 }
2185                 if (CPLGetLastErrorType() != CE_None) {
2186                     if (!bSkipFailures) {
2187                         ret = OGRERR_FAILURE;
2188                         goto done;
2189                     } else {
2190                         CPLErrorReset();
2191                         ret = OGRERR_NONE;
2192                         continue;
2193                     }
2194                 }
2195             }
2196             if (!z_geom) {
2197                 CPLErrorReset();
2198                 z_geom.reset(x_geom->Intersection(y_geom));
2199                 if (CPLGetLastErrorType() != CE_None || z_geom == nullptr) {
2200                     if (!bSkipFailures) {
2201                         ret = OGRERR_FAILURE;
2202                         goto done;
2203                     } else {
2204                         CPLErrorReset();
2205                         ret = OGRERR_NONE;
2206                         continue;
2207                     }
2208                 }
2209                 if (z_geom->IsEmpty() ||
2210                     (!bKeepLowerDimGeom &&
2211                      (x_geom->getDimension() == y_geom->getDimension() &&
2212                       z_geom->getDimension() < x_geom->getDimension())))
2213                 {
2214                     continue;
2215                 }
2216             }
2217             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
2218             z->SetFieldsFrom(x.get(), mapInput);
2219             z->SetFieldsFrom(y.get(), mapMethod);
2220             if (bPromoteToMulti)
2221                 z_geom.reset(promote_to_multi(z_geom.release()));
2222             z->SetGeometryDirectly(z_geom.release());
2223             ret = pLayerResult->CreateFeature(z.get());
2224 
2225             if (ret != OGRERR_NONE) {
2226                 if (!bSkipFailures) {
2227                     goto done;
2228                 } else {
2229                     CPLErrorReset();
2230                     ret = OGRERR_NONE;
2231                 }
2232             }
2233         }
2234     }
2235     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg)) {
2236       CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
2237       ret = OGRERR_FAILURE;
2238       goto done;
2239     }
2240 done:
2241     // release resources
2242     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
2243     if (pGeometryMethodFilter) delete pGeometryMethodFilter;
2244     if (mapInput) VSIFree(mapInput);
2245     if (mapMethod) VSIFree(mapMethod);
2246     return ret;
2247 }
2248 
2249 /************************************************************************/
2250 /*                       OGR_L_Intersection()                           */
2251 /************************************************************************/
2252 /**
2253  * \brief Intersection of two layers.
2254  *
2255  * The result layer contains features whose geometries represent areas
2256  * that are common between features in the input layer and in the
2257  * method layer. The features in the result layer have attributes from
2258  * both input and method layers. The schema of the result layer can be
2259  * set by the user or, if it is empty, is initialized to contain all
2260  * fields in the input and method layers.
2261  *
2262  * \note If the schema of the result is set by user and contains
2263  * fields that have the same name as a field in input and in method
2264  * layer, then the attribute in the result feature will get the value
2265  * from the feature of the method layer.
2266  *
2267  * \note For best performance use the minimum amount of features in
2268  * the method layer and copy it into a memory layer.
2269  *
2270  * \note This method relies on GEOS support. Do not use unless the
2271  * GEOS support is compiled in.
2272  *
2273  * The recognized list of options is :
2274  * <ul>
2275  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
2276  *     feature could not be inserted or a GEOS call failed.
2277  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
2278  *     into MultiPolygons, or LineStrings to MultiLineStrings.
2279  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
2280  *     will be created from the fields of the input layer.
2281  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
2282  *     will be created from the fields of the method layer.
2283  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
2284  *     geometries to pretest intersection of features of method layer
2285  *     with features of this layer.
2286  * <li>PRETEST_CONTAINMENT=YES/NO. Set to YES to pretest the
2287  *     containment of features of method layer within the features of
2288  *     this layer. This will speed up the method significantly in some
2289  *     cases. Requires that the prepared geometries are in effect.
2290  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
2291  *     result features with lower dimension geometry that would
2292  *     otherwise be added to the result layer. The default is to add
2293  *     but only if the result layer has an unknown geometry type.
2294  * </ul>
2295  *
2296  * This function is the same as the C++ method OGRLayer::Intersection().
2297  *
2298  * @param pLayerInput the input layer. Should not be NULL.
2299  *
2300  * @param pLayerMethod the method layer. Should not be NULL.
2301  *
2302  * @param pLayerResult the layer where the features resulting from the
2303  * operation are inserted. Should not be NULL. See above the note
2304  * about the schema.
2305  *
2306  * @param papszOptions NULL terminated list of options (may be NULL).
2307  *
2308  * @param pfnProgress a GDALProgressFunc() compatible callback function for
2309  * reporting progress or NULL.
2310  *
2311  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
2312  *
2313  * @return an error code if there was an error or the execution was
2314  * interrupted, OGRERR_NONE otherwise.
2315  *
2316  * @note The first geometry field is always used.
2317  *
2318  * @since OGR 1.10
2319  */
2320 
OGR_L_Intersection(OGRLayerH pLayerInput,OGRLayerH pLayerMethod,OGRLayerH pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)2321 OGRErr OGR_L_Intersection( OGRLayerH pLayerInput,
2322                            OGRLayerH pLayerMethod,
2323                            OGRLayerH pLayerResult,
2324                            char** papszOptions,
2325                            GDALProgressFunc pfnProgress,
2326                            void * pProgressArg )
2327 
2328 {
2329     VALIDATE_POINTER1( pLayerInput, "OGR_L_Intersection", OGRERR_INVALID_HANDLE );
2330     VALIDATE_POINTER1( pLayerMethod, "OGR_L_Intersection", OGRERR_INVALID_HANDLE );
2331     VALIDATE_POINTER1( pLayerResult, "OGR_L_Intersection", OGRERR_INVALID_HANDLE );
2332 
2333     return OGRLayer::FromHandle(pLayerInput)->Intersection(
2334         OGRLayer::FromHandle(pLayerMethod),
2335         OGRLayer::FromHandle(pLayerResult),
2336         papszOptions, pfnProgress, pProgressArg );
2337 }
2338 
2339 /************************************************************************/
2340 /*                              Union()                                 */
2341 /************************************************************************/
2342 
2343 /**
2344  * \brief Union of two layers.
2345  *
2346  * The result layer contains features whose geometries represent areas
2347  * that are either in the input layer, in the method layer, or in
2348  * both. The features in the result layer have attributes from both
2349  * input and method layers. For features which represent areas that
2350  * are only in the input or in the method layer the respective
2351  * attributes have undefined values. The schema of the result layer
2352  * can be set by the user or, if it is empty, is initialized to
2353  * contain all fields in the input and method layers.
2354  *
2355  * \note If the schema of the result is set by user and contains
2356  * fields that have the same name as a field in input and in method
2357  * layer, then the attribute in the result feature will get the value
2358  * from the feature of the method layer (even if it is undefined).
2359  *
2360  * \note For best performance use the minimum amount of features in
2361  * the method layer and copy it into a memory layer.
2362  *
2363  * \note This method relies on GEOS support. Do not use unless the
2364  * GEOS support is compiled in.
2365  *
2366  * The recognized list of options is :
2367  * <ul>
2368  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
2369  *     feature could not be inserted or a GEOS call failed.
2370  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
2371  *     into MultiPolygons, or LineStrings to MultiLineStrings.
2372  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
2373  *     will be created from the fields of the input layer.
2374  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
2375  *     will be created from the fields of the method layer.
2376  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
2377  *     geometries to pretest intersection of features of method layer
2378  *     with features of this layer.
2379  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
2380  *     result features with lower dimension geometry that would
2381  *     otherwise be added to the result layer. The default is to add
2382  *     but only if the result layer has an unknown geometry type.
2383  * </ul>
2384  *
2385  * This method is the same as the C function OGR_L_Union().
2386  *
2387  * @param pLayerMethod the method layer. Should not be NULL.
2388  *
2389  * @param pLayerResult the layer where the features resulting from the
2390  * operation are inserted. Should not be NULL. See above the note
2391  * about the schema.
2392  *
2393  * @param papszOptions NULL terminated list of options (may be NULL).
2394  *
2395  * @param pfnProgress a GDALProgressFunc() compatible callback function for
2396  * reporting progress or NULL.
2397  *
2398  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
2399  *
2400  * @return an error code if there was an error or the execution was
2401  * interrupted, OGRERR_NONE otherwise.
2402  *
2403  * @note The first geometry field is always used.
2404  *
2405  * @since OGR 1.10
2406  */
2407 
Union(OGRLayer * pLayerMethod,OGRLayer * pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)2408 OGRErr OGRLayer::Union( OGRLayer *pLayerMethod,
2409                         OGRLayer *pLayerResult,
2410                         char** papszOptions,
2411                         GDALProgressFunc pfnProgress,
2412                         void * pProgressArg )
2413 {
2414     OGRErr ret = OGRERR_NONE;
2415     OGRFeatureDefn *poDefnInput = GetLayerDefn();
2416     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
2417     OGRFeatureDefn *poDefnResult = nullptr;
2418     OGRGeometry *pGeometryMethodFilter = nullptr;
2419     OGRGeometry *pGeometryInputFilter = nullptr;
2420     int *mapInput = nullptr;
2421     int *mapMethod = nullptr;
2422     double progress_max = static_cast<double>(GetFeatureCount(FALSE)) + static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
2423     double progress_counter = 0;
2424     double progress_ticker = 0;
2425     int bSkipFailures = CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
2426     int bPromoteToMulti = CPLTestBool(CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
2427     int bUsePreparedGeometries = CPLTestBool(CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
2428     if (bUsePreparedGeometries) bUsePreparedGeometries = OGRHasPreparedGeometrySupport();
2429     int bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
2430 
2431     // check for GEOS
2432     if (!OGRGeometryFactory::haveGEOS()) {
2433         return OGRERR_UNSUPPORTED_OPERATION;
2434     }
2435 
2436     // get resources
2437     ret = clone_spatial_filter(this, &pGeometryInputFilter);
2438     if (ret != OGRERR_NONE) goto done;
2439     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
2440     if (ret != OGRERR_NONE) goto done;
2441     ret = create_field_map(poDefnInput, &mapInput);
2442     if (ret != OGRERR_NONE) goto done;
2443     ret = create_field_map(poDefnMethod, &mapMethod);
2444     if (ret != OGRERR_NONE) goto done;
2445     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput, mapMethod, true, papszOptions);
2446     if (ret != OGRERR_NONE) goto done;
2447     poDefnResult = pLayerResult->GetLayerDefn();
2448     if (bKeepLowerDimGeom) {
2449         // require that the result layer is of geom type unknown
2450         if (pLayerResult->GetGeomType() != wkbUnknown) {
2451             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO since the result layer does not allow it.");
2452             bKeepLowerDimGeom = FALSE;
2453         }
2454     }
2455 
2456     // add features based on input layer
2457     for( auto&& x: this ) {
2458 
2459         if (pfnProgress) {
2460             double p = progress_counter/progress_max;
2461             if (p > progress_ticker) {
2462                 if (!pfnProgress(p, "", pProgressArg)) {
2463                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
2464                     ret = OGRERR_FAILURE;
2465                     goto done;
2466                 }
2467             }
2468             progress_counter += 1.0;
2469         }
2470 
2471         // set up the filter on method layer
2472         CPLErrorReset();
2473         OGRGeometry *x_geom = set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
2474         if (CPLGetLastErrorType() != CE_None) {
2475             if (!bSkipFailures) {
2476                 ret = OGRERR_FAILURE;
2477                 goto done;
2478             } else {
2479                 CPLErrorReset();
2480                 ret = OGRERR_NONE;
2481             }
2482         }
2483         if (!x_geom) {
2484             continue;
2485         }
2486 
2487         OGRPreparedGeometryUniquePtr x_prepared_geom;
2488         if (bUsePreparedGeometries) {
2489             x_prepared_geom.reset(OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
2490             if (!x_prepared_geom) {
2491                 goto done;
2492             }
2493         }
2494 
2495         OGRGeometryUniquePtr x_geom_diff(x_geom->clone()); // this will be the geometry of the result feature
2496         for( auto&& y: pLayerMethod) {
2497             OGRGeometry *y_geom = y->GetGeometryRef();
2498             if (!y_geom) { continue;}
2499 
2500             CPLErrorReset();
2501             if (x_prepared_geom && !(OGRPreparedGeometryIntersects(x_prepared_geom.get(), OGRGeometry::ToHandle(y_geom)))) {
2502                 if (CPLGetLastErrorType() == CE_None) {
2503                     continue;
2504                 }
2505             }
2506             if (CPLGetLastErrorType() != CE_None) {
2507                 if (!bSkipFailures) {
2508                     ret = OGRERR_FAILURE;
2509                     goto done;
2510                 } else {
2511                     CPLErrorReset();
2512                     ret = OGRERR_NONE;
2513                 }
2514             }
2515 
2516             CPLErrorReset();
2517             OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
2518             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr) {
2519                 if (!bSkipFailures) {
2520                     ret = OGRERR_FAILURE;
2521                     goto done;
2522                 } else {
2523                     CPLErrorReset();
2524                     ret = OGRERR_NONE;
2525                     continue;
2526                 }
2527             }
2528             if( poIntersection->IsEmpty() ||
2529                 (!bKeepLowerDimGeom &&
2530                  (x_geom->getDimension() == y_geom->getDimension() &&
2531                   poIntersection->getDimension() < x_geom->getDimension())) )
2532             {
2533                 // ok
2534             }
2535             else
2536             {
2537                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
2538                 z->SetFieldsFrom(x.get(), mapInput);
2539                 z->SetFieldsFrom(y.get(), mapMethod);
2540                 if( bPromoteToMulti )
2541                     poIntersection.reset(promote_to_multi(poIntersection.release()));
2542                 z->SetGeometryDirectly(poIntersection.release());
2543 
2544                 if (x_geom_diff) {
2545                     CPLErrorReset();
2546                     OGRGeometryUniquePtr x_geom_diff_new(x_geom_diff->Difference(y_geom));
2547                     if (CPLGetLastErrorType() != CE_None || x_geom_diff_new == nullptr) {
2548                         if (!bSkipFailures) {
2549                             ret = OGRERR_FAILURE;
2550                             goto done;
2551                         } else {
2552                             CPLErrorReset();
2553                         }
2554                     } else {
2555                         x_geom_diff.swap(x_geom_diff_new);
2556                     }
2557                 }
2558 
2559                 ret = pLayerResult->CreateFeature(z.get());
2560                 if (ret != OGRERR_NONE) {
2561                     if (!bSkipFailures) {
2562                         goto done;
2563                     } else {
2564                         CPLErrorReset();
2565                         ret = OGRERR_NONE;
2566                     }
2567                 }
2568             }
2569         }
2570         x_prepared_geom.reset();
2571 
2572         if( x_geom_diff == nullptr || x_geom_diff->IsEmpty() )
2573         {
2574             // ok
2575         }
2576         else
2577         {
2578             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
2579             z->SetFieldsFrom(x.get(), mapInput);
2580             if( bPromoteToMulti )
2581                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
2582             z->SetGeometryDirectly(x_geom_diff.release());
2583             ret = pLayerResult->CreateFeature(z.get());
2584             if (ret != OGRERR_NONE) {
2585                 if (!bSkipFailures) {
2586                     goto done;
2587                 } else {
2588                     CPLErrorReset();
2589                     ret = OGRERR_NONE;
2590                 }
2591             }
2592         }
2593     }
2594 
2595     // restore filter on method layer and add features based on it
2596     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
2597     for( auto&& x: pLayerMethod ) {
2598 
2599         if (pfnProgress) {
2600             double p = progress_counter/progress_max;
2601             if (p > progress_ticker) {
2602                 if (!pfnProgress(p, "", pProgressArg)) {
2603                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
2604                     ret = OGRERR_FAILURE;
2605                     goto done;
2606                 }
2607             }
2608             progress_counter += 1.0;
2609         }
2610 
2611         // set up the filter on input layer
2612         CPLErrorReset();
2613         OGRGeometry *x_geom = set_filter_from(this, pGeometryInputFilter, x.get());
2614         if (CPLGetLastErrorType() != CE_None) {
2615             if (!bSkipFailures) {
2616                 ret = OGRERR_FAILURE;
2617                 goto done;
2618             } else {
2619                 CPLErrorReset();
2620                 ret = OGRERR_NONE;
2621             }
2622         }
2623         if (!x_geom) {
2624             continue;
2625         }
2626 
2627         OGRGeometryUniquePtr x_geom_diff(x_geom->clone()); // this will be the geometry of the result feature
2628         for( auto&& y: this ) {
2629             OGRGeometry *y_geom = y->GetGeometryRef();
2630             if (!y_geom) { continue;}
2631 
2632             if (x_geom_diff) {
2633                 CPLErrorReset();
2634                 OGRGeometryUniquePtr x_geom_diff_new(x_geom_diff->Difference(y_geom));
2635                 if (CPLGetLastErrorType() != CE_None || x_geom_diff_new == nullptr) {
2636                     if (!bSkipFailures) {
2637                         ret = OGRERR_FAILURE;
2638                         goto done;
2639                     } else {
2640                         CPLErrorReset();
2641                         ret = OGRERR_NONE;
2642                     }
2643                 } else {
2644                     x_geom_diff.swap(x_geom_diff_new);
2645                 }
2646             }
2647         }
2648 
2649         if( x_geom_diff == nullptr || x_geom_diff->IsEmpty() )
2650         {
2651             // ok
2652         }
2653         else
2654         {
2655             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
2656             z->SetFieldsFrom(x.get(), mapMethod);
2657             if( bPromoteToMulti )
2658                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
2659             z->SetGeometryDirectly(x_geom_diff.release());
2660             ret = pLayerResult->CreateFeature(z.get());
2661             if (ret != OGRERR_NONE) {
2662                 if (!bSkipFailures) {
2663                     goto done;
2664                 } else {
2665                     CPLErrorReset();
2666                     ret = OGRERR_NONE;
2667                 }
2668             }
2669         }
2670     }
2671     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg)) {
2672       CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
2673       ret = OGRERR_FAILURE;
2674       goto done;
2675     }
2676 done:
2677     // release resources
2678     SetSpatialFilter(pGeometryInputFilter);
2679     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
2680     if (pGeometryMethodFilter) delete pGeometryMethodFilter;
2681     if (pGeometryInputFilter) delete pGeometryInputFilter;
2682     if (mapInput) VSIFree(mapInput);
2683     if (mapMethod) VSIFree(mapMethod);
2684     return ret;
2685 }
2686 
2687 /************************************************************************/
2688 /*                           OGR_L_Union()                              */
2689 /************************************************************************/
2690 
2691 /**
2692  * \brief Union of two layers.
2693  *
2694  * The result layer contains features whose geometries represent areas
2695  * that are in either in the input layer, in the method layer, or in
2696  * both. The features in the result layer have attributes from both
2697  * input and method layers. For features which represent areas that
2698  * are only in the input or in the method layer the respective
2699  * attributes have undefined values. The schema of the result layer
2700  * can be set by the user or, if it is empty, is initialized to
2701  * contain all fields in the input and method layers.
2702  *
2703  * \note If the schema of the result is set by user and contains
2704  * fields that have the same name as a field in input and in method
2705  * layer, then the attribute in the result feature will get the value
2706  * from the feature of the method layer (even if it is undefined).
2707  *
2708  * \note For best performance use the minimum amount of features in
2709  * the method layer and copy it into a memory layer.
2710  *
2711  * \note This method relies on GEOS support. Do not use unless the
2712  * GEOS support is compiled in.
2713  *
2714  * The recognized list of options is :
2715  * <ul>
2716  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
2717  *     feature could not be inserted or a GEOS call failed.
2718  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
2719  *     into MultiPolygons, or LineStrings to MultiLineStrings.
2720  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
2721  *     will be created from the fields of the input layer.
2722  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
2723  *     will be created from the fields of the method layer.
2724  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
2725  *     geometries to pretest intersection of features of method layer
2726  *     with features of this layer.
2727  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
2728  *     result features with lower dimension geometry that would
2729  *     otherwise be added to the result layer. The default is to add
2730  *     but only if the result layer has an unknown geometry type.
2731  * </ul>
2732  *
2733  * This function is the same as the C++ method OGRLayer::Union().
2734  *
2735  * @param pLayerInput the input layer. Should not be NULL.
2736  *
2737  * @param pLayerMethod the method layer. Should not be NULL.
2738  *
2739  * @param pLayerResult the layer where the features resulting from the
2740  * operation are inserted. Should not be NULL. See above the note
2741  * about the schema.
2742  *
2743  * @param papszOptions NULL terminated list of options (may be NULL).
2744  *
2745  * @param pfnProgress a GDALProgressFunc() compatible callback function for
2746  * reporting progress or NULL.
2747  *
2748  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
2749  *
2750  * @return an error code if there was an error or the execution was
2751  * interrupted, OGRERR_NONE otherwise.
2752  *
2753  * @note The first geometry field is always used.
2754  *
2755  * @since OGR 1.10
2756  */
2757 
OGR_L_Union(OGRLayerH pLayerInput,OGRLayerH pLayerMethod,OGRLayerH pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)2758 OGRErr OGR_L_Union( OGRLayerH pLayerInput,
2759                     OGRLayerH pLayerMethod,
2760                     OGRLayerH pLayerResult,
2761                     char** papszOptions,
2762                     GDALProgressFunc pfnProgress,
2763                     void * pProgressArg )
2764 
2765 {
2766     VALIDATE_POINTER1( pLayerInput, "OGR_L_Union", OGRERR_INVALID_HANDLE );
2767     VALIDATE_POINTER1( pLayerMethod, "OGR_L_Union", OGRERR_INVALID_HANDLE );
2768     VALIDATE_POINTER1( pLayerResult, "OGR_L_Union", OGRERR_INVALID_HANDLE );
2769 
2770     return OGRLayer::FromHandle(pLayerInput)->Union(
2771         OGRLayer::FromHandle(pLayerMethod),
2772         OGRLayer::FromHandle(pLayerResult),
2773         papszOptions, pfnProgress, pProgressArg );
2774 }
2775 
2776 /************************************************************************/
2777 /*                          SymDifference()                             */
2778 /************************************************************************/
2779 
2780 /**
2781  * \brief Symmetrical difference of two layers.
2782  *
2783  * The result layer contains features whose geometries represent areas
2784  * that are in either in the input layer or in the method layer but
2785  * not in both. The features in the result layer have attributes from
2786  * both input and method layers. For features which represent areas
2787  * that are only in the input or in the method layer the respective
2788  * attributes have undefined values. The schema of the result layer
2789  * can be set by the user or, if it is empty, is initialized to
2790  * contain all fields in the input and method layers.
2791  *
2792  * \note If the schema of the result is set by user and contains
2793  * fields that have the same name as a field in input and in method
2794  * layer, then the attribute in the result feature will get the value
2795  * from the feature of the method layer (even if it is undefined).
2796  *
2797  * \note For best performance use the minimum amount of features in
2798  * the method layer and copy it into a memory layer.
2799  *
2800  * \note This method relies on GEOS support. Do not use unless the
2801  * GEOS support is compiled in.
2802  *
2803  * The recognized list of options is :
2804  * <ul>
2805  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
2806  *     feature could not be inserted or a GEOS call failed.
2807  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
2808  *     into MultiPolygons, or LineStrings to MultiLineStrings.
2809  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
2810  *     will be created from the fields of the input layer.
2811  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
2812  *     will be created from the fields of the method layer.
2813  * </ul>
2814  *
2815  * This method is the same as the C function OGR_L_SymDifference().
2816  *
2817  * @param pLayerMethod the method layer. Should not be NULL.
2818  *
2819  * @param pLayerResult the layer where the features resulting from the
2820  * operation are inserted. Should not be NULL. See above the note
2821  * about the schema.
2822  *
2823  * @param papszOptions NULL terminated list of options (may be NULL).
2824  *
2825  * @param pfnProgress a GDALProgressFunc() compatible callback function for
2826  * reporting progress or NULL.
2827  *
2828  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
2829  *
2830  * @return an error code if there was an error or the execution was
2831  * interrupted, OGRERR_NONE otherwise.
2832  *
2833  * @note The first geometry field is always used.
2834  *
2835  * @since OGR 1.10
2836  */
2837 
SymDifference(OGRLayer * pLayerMethod,OGRLayer * pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)2838 OGRErr OGRLayer::SymDifference( OGRLayer *pLayerMethod,
2839                                 OGRLayer *pLayerResult,
2840                                 char** papszOptions,
2841                                 GDALProgressFunc pfnProgress,
2842                                 void * pProgressArg )
2843 {
2844     OGRErr ret = OGRERR_NONE;
2845     OGRFeatureDefn *poDefnInput = GetLayerDefn();
2846     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
2847     OGRFeatureDefn *poDefnResult = nullptr;
2848     OGRGeometry *pGeometryMethodFilter = nullptr;
2849     OGRGeometry *pGeometryInputFilter = nullptr;
2850     int *mapInput = nullptr;
2851     int *mapMethod = nullptr;
2852     double progress_max = static_cast<double>(GetFeatureCount(FALSE)) + static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
2853     double progress_counter = 0;
2854     double progress_ticker = 0;
2855     int bSkipFailures = CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
2856     int bPromoteToMulti = CPLTestBool(CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
2857 
2858     // check for GEOS
2859     if (!OGRGeometryFactory::haveGEOS()) {
2860         return OGRERR_UNSUPPORTED_OPERATION;
2861     }
2862 
2863     // get resources
2864     ret = clone_spatial_filter(this, &pGeometryInputFilter);
2865     if (ret != OGRERR_NONE) goto done;
2866     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
2867     if (ret != OGRERR_NONE) goto done;
2868     ret = create_field_map(poDefnInput, &mapInput);
2869     if (ret != OGRERR_NONE) goto done;
2870     ret = create_field_map(poDefnMethod, &mapMethod);
2871     if (ret != OGRERR_NONE) goto done;
2872     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput, mapMethod, true, papszOptions);
2873     if (ret != OGRERR_NONE) goto done;
2874     poDefnResult = pLayerResult->GetLayerDefn();
2875 
2876     // add features based on input layer
2877     for( auto&& x: this ) {
2878 
2879         if (pfnProgress) {
2880             double p = progress_counter/progress_max;
2881             if (p > progress_ticker) {
2882                 if (!pfnProgress(p, "", pProgressArg)) {
2883                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
2884                     ret = OGRERR_FAILURE;
2885                     goto done;
2886                 }
2887             }
2888             progress_counter += 1.0;
2889         }
2890 
2891         // set up the filter on method layer
2892         CPLErrorReset();
2893         OGRGeometry *x_geom = set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
2894         if (CPLGetLastErrorType() != CE_None) {
2895             if (!bSkipFailures) {
2896                 ret = OGRERR_FAILURE;
2897                 goto done;
2898             } else {
2899                 CPLErrorReset();
2900                 ret = OGRERR_NONE;
2901             }
2902         }
2903         if (!x_geom) {
2904             continue;
2905         }
2906 
2907         OGRGeometryUniquePtr geom(x_geom->clone()); // this will be the geometry of the result feature
2908         for( auto&& y: pLayerMethod ) {
2909             OGRGeometry *y_geom = y->GetGeometryRef();
2910             if (!y_geom) {continue;}
2911             if (geom) {
2912                 CPLErrorReset();
2913                 OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
2914                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr) {
2915                     if (!bSkipFailures) {
2916                         ret = OGRERR_FAILURE;
2917                         goto done;
2918                     } else {
2919                         CPLErrorReset();
2920                         ret = OGRERR_NONE;
2921                     }
2922                 } else {
2923                     geom.swap(geom_new);
2924                 }
2925             }
2926             if (geom && geom->IsEmpty()) break;
2927         }
2928 
2929         if (geom && !geom->IsEmpty()) {
2930             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
2931             z->SetFieldsFrom(x.get(), mapInput);
2932             if( bPromoteToMulti )
2933                 geom.reset(promote_to_multi(geom.release()));
2934             z->SetGeometryDirectly(geom.release());
2935             ret = pLayerResult->CreateFeature(z.get());
2936             if (ret != OGRERR_NONE) {
2937                 if (!bSkipFailures) {
2938                     goto done;
2939                 } else {
2940                     CPLErrorReset();
2941                     ret = OGRERR_NONE;
2942                 }
2943             }
2944         }
2945     }
2946 
2947     // restore filter on method layer and add features based on it
2948     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
2949     for( auto&& x: pLayerMethod ) {
2950 
2951         if (pfnProgress) {
2952             double p = progress_counter/progress_max;
2953             if (p > progress_ticker) {
2954                 if (!pfnProgress(p, "", pProgressArg)) {
2955                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
2956                     ret = OGRERR_FAILURE;
2957                     goto done;
2958                 }
2959             }
2960             progress_counter += 1.0;
2961         }
2962 
2963         // set up the filter on input layer
2964         CPLErrorReset();
2965         OGRGeometry *x_geom = set_filter_from(this, pGeometryInputFilter, x.get());
2966         if (CPLGetLastErrorType() != CE_None) {
2967             if (!bSkipFailures) {
2968                 ret = OGRERR_FAILURE;
2969                 goto done;
2970             } else {
2971                 CPLErrorReset();
2972                 ret = OGRERR_NONE;
2973             }
2974         }
2975         if (!x_geom) {
2976             continue;
2977         }
2978 
2979         OGRGeometryUniquePtr geom(x_geom->clone()); // this will be the geometry of the result feature
2980         for( auto&& y: this ) {
2981             OGRGeometry *y_geom = y->GetGeometryRef();
2982             if (!y_geom) continue;
2983             if (geom) {
2984                 CPLErrorReset();
2985                 OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
2986                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr) {
2987                     if (!bSkipFailures) {
2988                         ret = OGRERR_FAILURE;
2989                         goto done;
2990                     } else {
2991                         CPLErrorReset();
2992                         ret = OGRERR_NONE;
2993                     }
2994                 } else {
2995                     geom.swap(geom_new);
2996                 }
2997             }
2998             if (geom == nullptr || geom->IsEmpty()) break;
2999         }
3000 
3001         if (geom && !geom->IsEmpty()) {
3002             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3003             z->SetFieldsFrom(x.get(), mapMethod);
3004             if( bPromoteToMulti )
3005                 geom.reset(promote_to_multi(geom.release()));
3006             z->SetGeometryDirectly(geom.release());
3007             ret = pLayerResult->CreateFeature(z.get());
3008             if (ret != OGRERR_NONE) {
3009                 if (!bSkipFailures) {
3010                     goto done;
3011                 } else {
3012                     CPLErrorReset();
3013                     ret = OGRERR_NONE;
3014                 }
3015             }
3016         }
3017     }
3018     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg)) {
3019       CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3020       ret = OGRERR_FAILURE;
3021       goto done;
3022     }
3023 done:
3024     // release resources
3025     SetSpatialFilter(pGeometryInputFilter);
3026     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3027     if (pGeometryMethodFilter) delete pGeometryMethodFilter;
3028     if (pGeometryInputFilter) delete pGeometryInputFilter;
3029     if (mapInput) VSIFree(mapInput);
3030     if (mapMethod) VSIFree(mapMethod);
3031     return ret;
3032 }
3033 
3034 /************************************************************************/
3035 /*                        OGR_L_SymDifference()                         */
3036 /************************************************************************/
3037 
3038 /**
3039  * \brief Symmetrical difference of two layers.
3040  *
3041  * The result layer contains features whose geometries represent areas
3042  * that are in either in the input layer or in the method layer but
3043  * not in both. The features in the result layer have attributes from
3044  * both input and method layers. For features which represent areas
3045  * that are only in the input or in the method layer the respective
3046  * attributes have undefined values. The schema of the result layer
3047  * can be set by the user or, if it is empty, is initialized to
3048  * contain all fields in the input and method layers.
3049  *
3050  * \note If the schema of the result is set by user and contains
3051  * fields that have the same name as a field in input and in method
3052  * layer, then the attribute in the result feature will get the value
3053  * from the feature of the method layer (even if it is undefined).
3054  *
3055  * \note For best performance use the minimum amount of features in
3056  * the method layer and copy it into a memory layer.
3057  *
3058  * \note This method relies on GEOS support. Do not use unless the
3059  * GEOS support is compiled in.
3060  *
3061  * The recognized list of options is :
3062  * <ul>
3063  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3064  *     feature could not be inserted or a GEOS call failed.
3065  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
3066  *     into MultiPolygons, or LineStrings to MultiLineStrings.
3067  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3068  *     will be created from the fields of the input layer.
3069  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3070  *     will be created from the fields of the method layer.
3071  * </ul>
3072  *
3073  * This function is the same as the C++ method OGRLayer::SymDifference().
3074  *
3075  * @param pLayerInput the input layer. Should not be NULL.
3076  *
3077  * @param pLayerMethod the method layer. Should not be NULL.
3078  *
3079  * @param pLayerResult the layer where the features resulting from the
3080  * operation are inserted. Should not be NULL. See above the note
3081  * about the schema.
3082  *
3083  * @param papszOptions NULL terminated list of options (may be NULL).
3084  *
3085  * @param pfnProgress a GDALProgressFunc() compatible callback function for
3086  * reporting progress or NULL.
3087  *
3088  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3089  *
3090  * @return an error code if there was an error or the execution was
3091  * interrupted, OGRERR_NONE otherwise.
3092  *
3093  * @note The first geometry field is always used.
3094  *
3095  * @since OGR 1.10
3096  */
3097 
OGR_L_SymDifference(OGRLayerH pLayerInput,OGRLayerH pLayerMethod,OGRLayerH pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)3098 OGRErr OGR_L_SymDifference( OGRLayerH pLayerInput,
3099                             OGRLayerH pLayerMethod,
3100                             OGRLayerH pLayerResult,
3101                             char** papszOptions,
3102                             GDALProgressFunc pfnProgress,
3103                             void * pProgressArg )
3104 
3105 {
3106     VALIDATE_POINTER1( pLayerInput, "OGR_L_SymDifference", OGRERR_INVALID_HANDLE );
3107     VALIDATE_POINTER1( pLayerMethod, "OGR_L_SymDifference", OGRERR_INVALID_HANDLE );
3108     VALIDATE_POINTER1( pLayerResult, "OGR_L_SymDifference", OGRERR_INVALID_HANDLE );
3109 
3110     return OGRLayer::FromHandle(pLayerInput)->SymDifference(
3111         OGRLayer::FromHandle(pLayerMethod),
3112         OGRLayer::FromHandle(pLayerResult),
3113         papszOptions, pfnProgress, pProgressArg );
3114 }
3115 
3116 /************************************************************************/
3117 /*                            Identity()                                */
3118 /************************************************************************/
3119 
3120 /**
3121  * \brief Identify the features of this layer with the ones from the
3122  * identity layer.
3123  *
3124  * The result layer contains features whose geometries represent areas
3125  * that are in the input layer. The features in the result layer have
3126  * attributes from both input and method layers. The schema of the
3127  * result layer can be set by the user or, if it is empty, is
3128  * initialized to contain all fields in input and method layers.
3129  *
3130  * \note If the schema of the result is set by user and contains
3131  * fields that have the same name as a field in input and in method
3132  * layer, then the attribute in the result feature will get the value
3133  * from the feature of the method layer (even if it is undefined).
3134  *
3135  * \note For best performance use the minimum amount of features in
3136  * the method layer and copy it into a memory layer.
3137  *
3138  * \note This method relies on GEOS support. Do not use unless the
3139  * GEOS support is compiled in.
3140  *
3141  * The recognized list of options is :
3142  * <ul>
3143  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3144  *     feature could not be inserted or a GEOS call failed.
3145  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
3146  *     into MultiPolygons, or LineStrings to MultiLineStrings.
3147  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3148  *     will be created from the fields of the input layer.
3149  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3150  *     will be created from the fields of the method layer.
3151  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3152  *     geometries to pretest intersection of features of method layer
3153  *     with features of this layer.
3154  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3155  *     result features with lower dimension geometry that would
3156  *     otherwise be added to the result layer. The default is to add
3157  *     but only if the result layer has an unknown geometry type.
3158  * </ul>
3159  *
3160  * This method is the same as the C function OGR_L_Identity().
3161  *
3162  * @param pLayerMethod the method layer. Should not be NULL.
3163  *
3164  * @param pLayerResult the layer where the features resulting from the
3165  * operation are inserted. Should not be NULL. See above the note
3166  * about the schema.
3167  *
3168  * @param papszOptions NULL terminated list of options (may be NULL).
3169  *
3170  * @param pfnProgress a GDALProgressFunc() compatible callback function for
3171  * reporting progress or NULL.
3172  *
3173  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3174  *
3175  * @return an error code if there was an error or the execution was
3176  * interrupted, OGRERR_NONE otherwise.
3177  *
3178  * @note The first geometry field is always used.
3179  *
3180  * @since OGR 1.10
3181  */
3182 
Identity(OGRLayer * pLayerMethod,OGRLayer * pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)3183 OGRErr OGRLayer::Identity( OGRLayer *pLayerMethod,
3184                            OGRLayer *pLayerResult,
3185                            char** papszOptions,
3186                            GDALProgressFunc pfnProgress,
3187                            void * pProgressArg )
3188 {
3189     OGRErr ret = OGRERR_NONE;
3190     OGRFeatureDefn *poDefnInput = GetLayerDefn();
3191     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3192     OGRFeatureDefn *poDefnResult = nullptr;
3193     OGRGeometry *pGeometryMethodFilter = nullptr;
3194     int *mapInput = nullptr;
3195     int *mapMethod = nullptr;
3196     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
3197     double progress_counter = 0;
3198     double progress_ticker = 0;
3199     int bSkipFailures = CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3200     int bPromoteToMulti = CPLTestBool(CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3201     int bUsePreparedGeometries = CPLTestBool(CSLFetchNameValueDef(papszOptions, "USE_PREPARED_GEOMETRIES", "YES"));
3202     if (bUsePreparedGeometries) bUsePreparedGeometries = OGRHasPreparedGeometrySupport();
3203     int bKeepLowerDimGeom = CPLTestBool(CSLFetchNameValueDef(papszOptions, "KEEP_LOWER_DIMENSION_GEOMETRIES", "YES"));
3204 
3205     // check for GEOS
3206     if (!OGRGeometryFactory::haveGEOS()) {
3207         return OGRERR_UNSUPPORTED_OPERATION;
3208     }
3209     if (bKeepLowerDimGeom) {
3210         // require that the result layer is of geom type unknown
3211         if (pLayerResult->GetGeomType() != wkbUnknown) {
3212             CPLDebug("OGR", "Resetting KEEP_LOWER_DIMENSION_GEOMETRIES to NO since the result layer does not allow it.");
3213             bKeepLowerDimGeom = FALSE;
3214         }
3215     }
3216 
3217     // get resources
3218     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3219     if (ret != OGRERR_NONE) goto done;
3220     ret = create_field_map(poDefnInput, &mapInput);
3221     if (ret != OGRERR_NONE) goto done;
3222     ret = create_field_map(poDefnMethod, &mapMethod);
3223     if (ret != OGRERR_NONE) goto done;
3224     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput, mapMethod, true, papszOptions);
3225     if (ret != OGRERR_NONE) goto done;
3226     poDefnResult = pLayerResult->GetLayerDefn();
3227 
3228     // split the features in input layer to the result layer
3229     for( auto&& x: this ) {
3230 
3231         if (pfnProgress) {
3232             double p = progress_counter/progress_max;
3233             if (p > progress_ticker) {
3234                 if (!pfnProgress(p, "", pProgressArg)) {
3235                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3236                     ret = OGRERR_FAILURE;
3237                     goto done;
3238                 }
3239             }
3240             progress_counter += 1.0;
3241         }
3242 
3243         // set up the filter on method layer
3244         CPLErrorReset();
3245         OGRGeometry *x_geom = set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3246         if (CPLGetLastErrorType() != CE_None) {
3247             if (!bSkipFailures) {
3248                 ret = OGRERR_FAILURE;
3249                 goto done;
3250             } else {
3251                 CPLErrorReset();
3252                 ret = OGRERR_NONE;
3253             }
3254         }
3255         if (!x_geom) {
3256             continue;
3257         }
3258 
3259         OGRPreparedGeometryUniquePtr x_prepared_geom;
3260         if (bUsePreparedGeometries) {
3261             x_prepared_geom.reset(OGRCreatePreparedGeometry(OGRGeometry::ToHandle(x_geom)));
3262             if (!x_prepared_geom) {
3263                 goto done;
3264             }
3265         }
3266 
3267         OGRGeometryUniquePtr x_geom_diff(x_geom->clone()); // this will be the geometry of the result feature
3268         for( auto&& y: pLayerMethod ) {
3269             OGRGeometry *y_geom = y->GetGeometryRef();
3270             if (!y_geom)
3271                 continue;
3272 
3273             CPLErrorReset();
3274             if (x_prepared_geom && !(OGRPreparedGeometryIntersects(x_prepared_geom.get(), OGRGeometry::ToHandle(y_geom)))) {
3275                 if (CPLGetLastErrorType() == CE_None) {
3276                     continue;
3277                 }
3278             }
3279             if (CPLGetLastErrorType() != CE_None) {
3280                 if (!bSkipFailures) {
3281                     ret = OGRERR_FAILURE;
3282                     goto done;
3283                 } else {
3284                     CPLErrorReset();
3285                     ret = OGRERR_NONE;
3286                 }
3287             }
3288 
3289             CPLErrorReset();
3290             OGRGeometryUniquePtr poIntersection(x_geom->Intersection(y_geom));
3291             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr) {
3292                 if (!bSkipFailures) {
3293                     ret = OGRERR_FAILURE;
3294                     goto done;
3295                 } else {
3296                     CPLErrorReset();
3297                     ret = OGRERR_NONE;
3298                 }
3299             }
3300             else if( poIntersection->IsEmpty() ||
3301                      (!bKeepLowerDimGeom &&
3302                       (x_geom->getDimension() == y_geom->getDimension() &&
3303                        poIntersection->getDimension() < x_geom->getDimension())) )
3304             {
3305                 /* ok*/
3306             }
3307             else
3308             {
3309                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3310                 z->SetFieldsFrom(x.get(), mapInput);
3311                 z->SetFieldsFrom(y.get(), mapMethod);
3312                 if( bPromoteToMulti )
3313                     poIntersection.reset(promote_to_multi(poIntersection.release()));
3314                 z->SetGeometryDirectly(poIntersection.release());
3315                 if (x_geom_diff) {
3316                     CPLErrorReset();
3317                     OGRGeometryUniquePtr x_geom_diff_new(x_geom_diff->Difference(y_geom));
3318                     if (CPLGetLastErrorType() != CE_None || x_geom_diff_new == nullptr) {
3319                         if (!bSkipFailures) {
3320                             ret = OGRERR_FAILURE;
3321                             goto done;
3322                         } else {
3323                             CPLErrorReset();
3324                         }
3325                     } else {
3326                         x_geom_diff.swap(x_geom_diff_new);
3327                     }
3328                 }
3329                 ret = pLayerResult->CreateFeature(z.get());
3330                 if (ret != OGRERR_NONE) {
3331                     if (!bSkipFailures) {
3332                         goto done;
3333                     } else {
3334                         CPLErrorReset();
3335                         ret = OGRERR_NONE;
3336                     }
3337                 }
3338             }
3339         }
3340 
3341         x_prepared_geom.reset();
3342 
3343         if( x_geom_diff == nullptr || x_geom_diff->IsEmpty() )
3344         {
3345             /* ok */
3346         }
3347         else
3348         {
3349             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3350             z->SetFieldsFrom(x.get(), mapInput);
3351             if( bPromoteToMulti )
3352                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
3353             z->SetGeometryDirectly(x_geom_diff.release());
3354             ret = pLayerResult->CreateFeature(z.get());
3355             if (ret != OGRERR_NONE) {
3356                 if (!bSkipFailures) {
3357                     goto done;
3358                 } else {
3359                     CPLErrorReset();
3360                     ret = OGRERR_NONE;
3361                 }
3362             }
3363         }
3364     }
3365     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg)) {
3366       CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3367       ret = OGRERR_FAILURE;
3368       goto done;
3369     }
3370 done:
3371     // release resources
3372     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3373     if (pGeometryMethodFilter) delete pGeometryMethodFilter;
3374     if (mapInput) VSIFree(mapInput);
3375     if (mapMethod) VSIFree(mapMethod);
3376     return ret;
3377 }
3378 
3379 /************************************************************************/
3380 /*                         OGR_L_Identity()                             */
3381 /************************************************************************/
3382 
3383 /**
3384  * \brief Identify the features of this layer with the ones from the
3385  * identity layer.
3386  *
3387  * The result layer contains features whose geometries represent areas
3388  * that are in the input layer. The features in the result layer have
3389  * attributes from both input and method layers. The schema of the
3390  * result layer can be set by the user or, if it is empty, is
3391  * initialized to contain all fields in input and method layers.
3392  *
3393  * \note If the schema of the result is set by user and contains
3394  * fields that have the same name as a field in input and in method
3395  * layer, then the attribute in the result feature will get the value
3396  * from the feature of the method layer (even if it is undefined).
3397  *
3398  * \note For best performance use the minimum amount of features in
3399  * the method layer and copy it into a memory layer.
3400  *
3401  * \note This method relies on GEOS support. Do not use unless the
3402  * GEOS support is compiled in.
3403  *
3404  * The recognized list of options is :
3405  * <ul>
3406  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3407  *     feature could not be inserted or a GEOS call failed.
3408  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
3409  *     into MultiPolygons, or LineStrings to MultiLineStrings.
3410  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3411  *     will be created from the fields of the input layer.
3412  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3413  *     will be created from the fields of the method layer.
3414  * <li>USE_PREPARED_GEOMETRIES=YES/NO. Set to NO to not use prepared
3415  *     geometries to pretest intersection of features of method layer
3416  *     with features of this layer.
3417  * <li>KEEP_LOWER_DIMENSION_GEOMETRIES=YES/NO. Set to NO to skip
3418  *     result features with lower dimension geometry that would
3419  *     otherwise be added to the result layer. The default is to add
3420  *     but only if the result layer has an unknown geometry type.
3421  * </ul>
3422  *
3423  * This function is the same as the C++ method OGRLayer::Identity().
3424  *
3425  * @param pLayerInput the input layer. Should not be NULL.
3426  *
3427  * @param pLayerMethod the method layer. Should not be NULL.
3428  *
3429  * @param pLayerResult the layer where the features resulting from the
3430  * operation are inserted. Should not be NULL. See above the note
3431  * about the schema.
3432  *
3433  * @param papszOptions NULL terminated list of options (may be NULL).
3434  *
3435  * @param pfnProgress a GDALProgressFunc() compatible callback function for
3436  * reporting progress or NULL.
3437  *
3438  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3439  *
3440  * @return an error code if there was an error or the execution was
3441  * interrupted, OGRERR_NONE otherwise.
3442  *
3443  * @note The first geometry field is always used.
3444  *
3445  * @since OGR 1.10
3446  */
3447 
OGR_L_Identity(OGRLayerH pLayerInput,OGRLayerH pLayerMethod,OGRLayerH pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)3448 OGRErr OGR_L_Identity( OGRLayerH pLayerInput,
3449                        OGRLayerH pLayerMethod,
3450                        OGRLayerH pLayerResult,
3451                        char** papszOptions,
3452                        GDALProgressFunc pfnProgress,
3453                        void * pProgressArg )
3454 
3455 {
3456     VALIDATE_POINTER1( pLayerInput, "OGR_L_Identity", OGRERR_INVALID_HANDLE );
3457     VALIDATE_POINTER1( pLayerMethod, "OGR_L_Identity", OGRERR_INVALID_HANDLE );
3458     VALIDATE_POINTER1( pLayerResult, "OGR_L_Identity", OGRERR_INVALID_HANDLE );
3459 
3460     return OGRLayer::FromHandle(pLayerInput)->Identity(
3461         OGRLayer::FromHandle(pLayerMethod),
3462         OGRLayer::FromHandle(pLayerResult),
3463         papszOptions, pfnProgress, pProgressArg );
3464 }
3465 
3466 /************************************************************************/
3467 /*                             Update()                                 */
3468 /************************************************************************/
3469 
3470 /**
3471  * \brief Update this layer with features from the update layer.
3472  *
3473  * The result layer contains features whose geometries represent areas
3474  * that are either in the input layer or in the method layer. The
3475  * features in the result layer have areas of the features of the
3476  * method layer or those ares of the features of the input layer that
3477  * are not covered by the method layer. The features of the result
3478  * layer get their attributes from the input layer. The schema of the
3479  * result layer can be set by the user or, if it is empty, is
3480  * initialized to contain all fields in the input layer.
3481  *
3482  * \note If the schema of the result is set by user and contains
3483  * fields that have the same name as a field in the method layer, then
3484  * the attribute in the result feature the originates from the method
3485  * layer will get the value from the feature of the method layer.
3486  *
3487  * \note For best performance use the minimum amount of features in
3488  * the method layer and copy it into a memory layer.
3489  *
3490  * \note This method relies on GEOS support. Do not use unless the
3491  * GEOS support is compiled in.
3492  *
3493  * The recognized list of options is :
3494  * <ul>
3495  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3496  *     feature could not be inserted or a GEOS call failed.
3497  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
3498  *     into MultiPolygons, or LineStrings to MultiLineStrings.
3499  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3500  *     will be created from the fields of the input layer.
3501  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3502  *     will be created from the fields of the method layer.
3503  * </ul>
3504  *
3505  * This method is the same as the C function OGR_L_Update().
3506  *
3507  * @param pLayerMethod the method layer. Should not be NULL.
3508  *
3509  * @param pLayerResult the layer where the features resulting from the
3510  * operation are inserted. Should not be NULL. See above the note
3511  * about the schema.
3512  *
3513  * @param papszOptions NULL terminated list of options (may be NULL).
3514  *
3515  * @param pfnProgress a GDALProgressFunc() compatible callback function for
3516  * reporting progress or NULL.
3517  *
3518  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3519  *
3520  * @return an error code if there was an error or the execution was
3521  * interrupted, OGRERR_NONE otherwise.
3522  *
3523  * @note The first geometry field is always used.
3524  *
3525  * @since OGR 1.10
3526  */
3527 
Update(OGRLayer * pLayerMethod,OGRLayer * pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)3528 OGRErr OGRLayer::Update( OGRLayer *pLayerMethod,
3529                          OGRLayer *pLayerResult,
3530                          char** papszOptions,
3531                          GDALProgressFunc pfnProgress,
3532                          void * pProgressArg )
3533 {
3534     OGRErr ret = OGRERR_NONE;
3535     OGRFeatureDefn *poDefnInput = GetLayerDefn();
3536     OGRFeatureDefn *poDefnMethod = pLayerMethod->GetLayerDefn();
3537     OGRFeatureDefn *poDefnResult = nullptr;
3538     OGRGeometry *pGeometryMethodFilter = nullptr;
3539     int *mapInput = nullptr;
3540     int *mapMethod = nullptr;
3541     double progress_max = static_cast<double>(GetFeatureCount(FALSE)) + static_cast<double>(pLayerMethod->GetFeatureCount(FALSE));
3542     double progress_counter = 0;
3543     double progress_ticker = 0;
3544     int bSkipFailures = CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3545     int bPromoteToMulti = CPLTestBool(CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3546 
3547     // check for GEOS
3548     if (!OGRGeometryFactory::haveGEOS()) {
3549         return OGRERR_UNSUPPORTED_OPERATION;
3550     }
3551 
3552     // get resources
3553     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3554     if (ret != OGRERR_NONE) goto done;
3555     ret = create_field_map(poDefnInput, &mapInput);
3556     if (ret != OGRERR_NONE) goto done;
3557     ret = create_field_map(poDefnMethod, &mapMethod);
3558     if (ret != OGRERR_NONE) goto done;
3559     ret = set_result_schema(pLayerResult, poDefnInput, poDefnMethod, mapInput, mapMethod, false, papszOptions);
3560     if (ret != OGRERR_NONE) goto done;
3561     poDefnResult = pLayerResult->GetLayerDefn();
3562 
3563     // add clipped features from the input layer
3564     for( auto&& x: this ) {
3565 
3566         if (pfnProgress) {
3567             double p = progress_counter/progress_max;
3568             if (p > progress_ticker) {
3569                 if (!pfnProgress(p, "", pProgressArg)) {
3570                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3571                     ret = OGRERR_FAILURE;
3572                     goto done;
3573                 }
3574             }
3575             progress_counter += 1.0;
3576         }
3577 
3578         // set up the filter on method layer
3579         CPLErrorReset();
3580         OGRGeometry *x_geom = set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3581         if (CPLGetLastErrorType() != CE_None) {
3582             if (!bSkipFailures) {
3583                 ret = OGRERR_FAILURE;
3584                 goto done;
3585             } else {
3586                 CPLErrorReset();
3587                 ret = OGRERR_NONE;
3588             }
3589         }
3590         if (!x_geom) {
3591             continue;
3592         }
3593 
3594         OGRGeometryUniquePtr x_geom_diff(x_geom->clone()); //this will be the geometry of a result feature
3595         for( auto&& y: pLayerMethod ) {
3596             OGRGeometry *y_geom = y->GetGeometryRef();
3597             if (!y_geom) continue;
3598             if (x_geom_diff) {
3599                 CPLErrorReset();
3600                 OGRGeometryUniquePtr x_geom_diff_new(x_geom_diff->Difference(y_geom));
3601                 if (CPLGetLastErrorType() != CE_None || x_geom_diff_new == nullptr) {
3602                     if (!bSkipFailures) {
3603                         ret = OGRERR_FAILURE;
3604                         goto done;
3605                     } else {
3606                         CPLErrorReset();
3607                         ret = OGRERR_NONE;
3608                     }
3609                 } else {
3610                     x_geom_diff.swap(x_geom_diff_new);
3611                 }
3612             }
3613         }
3614 
3615         if( x_geom_diff == nullptr || x_geom_diff->IsEmpty() )
3616         {
3617             /* ok */
3618         }
3619         else
3620         {
3621             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3622             z->SetFieldsFrom(x.get(), mapInput);
3623             if( bPromoteToMulti )
3624                 x_geom_diff.reset(promote_to_multi(x_geom_diff.release()));
3625             z->SetGeometryDirectly(x_geom_diff.release());
3626             ret = pLayerResult->CreateFeature(z.get());
3627             if (ret != OGRERR_NONE) {
3628                 if (!bSkipFailures) {
3629                     goto done;
3630                 } else {
3631                     CPLErrorReset();
3632                     ret = OGRERR_NONE;
3633                 }
3634             }
3635         }
3636     }
3637 
3638     // restore the original filter and add features from the update layer
3639     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3640     for( auto&& y: pLayerMethod ) {
3641 
3642         if (pfnProgress) {
3643             double p = progress_counter/progress_max;
3644             if (p > progress_ticker) {
3645                 if (!pfnProgress(p, "", pProgressArg)) {
3646                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3647                     ret = OGRERR_FAILURE;
3648                     goto done;
3649                 }
3650             }
3651             progress_counter += 1.0;
3652         }
3653 
3654         OGRGeometry *y_geom = y->StealGeometry();
3655         if (!y_geom) continue;
3656         OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3657         if (mapMethod) z->SetFieldsFrom(y.get(), mapMethod);
3658         z->SetGeometryDirectly(y_geom);
3659         ret = pLayerResult->CreateFeature(z.get());
3660         if (ret != OGRERR_NONE) {
3661             if (!bSkipFailures) {
3662                 goto done;
3663             } else {
3664                 CPLErrorReset();
3665                 ret = OGRERR_NONE;
3666             }
3667         }
3668     }
3669     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg)) {
3670       CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3671       ret = OGRERR_FAILURE;
3672       goto done;
3673     }
3674 done:
3675     // release resources
3676     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3677     if (pGeometryMethodFilter) delete pGeometryMethodFilter;
3678     if (mapInput) VSIFree(mapInput);
3679     if (mapMethod) VSIFree(mapMethod);
3680     return ret;
3681 }
3682 
3683 /************************************************************************/
3684 /*                          OGR_L_Update()                              */
3685 /************************************************************************/
3686 
3687 /**
3688  * \brief Update this layer with features from the update layer.
3689  *
3690  * The result layer contains features whose geometries represent areas
3691  * that are either in the input layer or in the method layer. The
3692  * features in the result layer have areas of the features of the
3693  * method layer or those ares of the features of the input layer that
3694  * are not covered by the method layer. The features of the result
3695  * layer get their attributes from the input layer. The schema of the
3696  * result layer can be set by the user or, if it is empty, is
3697  * initialized to contain all fields in the input layer.
3698  *
3699  * \note If the schema of the result is set by user and contains
3700  * fields that have the same name as a field in the method layer, then
3701  * the attribute in the result feature the originates from the method
3702  * layer will get the value from the feature of the method layer.
3703  *
3704  * \note For best performance use the minimum amount of features in
3705  * the method layer and copy it into a memory layer.
3706  *
3707  * \note This method relies on GEOS support. Do not use unless the
3708  * GEOS support is compiled in.
3709  *
3710  * The recognized list of options is :
3711  * <ul>
3712  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3713  *     feature could not be inserted or a GEOS call failed.
3714  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
3715  *     into MultiPolygons, or LineStrings to MultiLineStrings.
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>METHOD_PREFIX=string. Set a prefix for the field names that
3719  *     will be created from the fields of the method layer.
3720  * </ul>
3721  *
3722  * This function is the same as the C++ method OGRLayer::Update().
3723  *
3724  * @param pLayerInput the input layer. Should not be NULL.
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 
OGR_L_Update(OGRLayerH pLayerInput,OGRLayerH pLayerMethod,OGRLayerH pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)3747 OGRErr OGR_L_Update( OGRLayerH pLayerInput,
3748                      OGRLayerH pLayerMethod,
3749                      OGRLayerH pLayerResult,
3750                      char** papszOptions,
3751                      GDALProgressFunc pfnProgress,
3752                      void * pProgressArg )
3753 
3754 {
3755     VALIDATE_POINTER1( pLayerInput, "OGR_L_Update", OGRERR_INVALID_HANDLE );
3756     VALIDATE_POINTER1( pLayerMethod, "OGR_L_Update", OGRERR_INVALID_HANDLE );
3757     VALIDATE_POINTER1( pLayerResult, "OGR_L_Update", OGRERR_INVALID_HANDLE );
3758 
3759     return OGRLayer::FromHandle(pLayerInput)->Update(
3760         OGRLayer::FromHandle(pLayerMethod),
3761         OGRLayer::FromHandle(pLayerResult),
3762         papszOptions, pfnProgress, pProgressArg );
3763 }
3764 
3765 /************************************************************************/
3766 /*                              Clip()                                  */
3767 /************************************************************************/
3768 
3769 /**
3770  * \brief Clip off areas that are not covered by the method layer.
3771  *
3772  * The result layer contains features whose geometries represent areas
3773  * that are in the input layer and in the method layer. The features
3774  * in the result layer have the (possibly clipped) areas of features
3775  * in the input layer and the attributes from the same features. The
3776  * schema of the result layer can be set by the user or, if it is
3777  * empty, is initialized to contain all fields in the input layer.
3778  *
3779  * \note For best performance use the minimum amount of features in
3780  * the method layer and copy it into a memory layer.
3781  *
3782  * \note This method relies on GEOS support. Do not use unless the
3783  * GEOS support is compiled in.
3784  *
3785  * The recognized list of options is :
3786  * <ul>
3787  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3788  *     feature could not be inserted or a GEOS call failed.
3789  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
3790  *     into MultiPolygons, or LineStrings to MultiLineStrings.
3791  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3792  *     will be created from the fields of the input layer.
3793  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3794  *     will be created from the fields of the method layer.
3795  * </ul>
3796  *
3797  * This method is the same as the C function OGR_L_Clip().
3798  *
3799  * @param pLayerMethod the method layer. Should not be NULL.
3800  *
3801  * @param pLayerResult the layer where the features resulting from the
3802  * operation are inserted. Should not be NULL. See above the note
3803  * about the schema.
3804  *
3805  * @param papszOptions NULL terminated list of options (may be NULL).
3806  *
3807  * @param pfnProgress a GDALProgressFunc() compatible callback function for
3808  * reporting progress or NULL.
3809  *
3810  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3811  *
3812  * @return an error code if there was an error or the execution was
3813  * interrupted, OGRERR_NONE otherwise.
3814  *
3815  * @note The first geometry field is always used.
3816  *
3817  * @since OGR 1.10
3818  */
3819 
Clip(OGRLayer * pLayerMethod,OGRLayer * pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)3820 OGRErr OGRLayer::Clip( OGRLayer *pLayerMethod,
3821                        OGRLayer *pLayerResult,
3822                        char** papszOptions,
3823                        GDALProgressFunc pfnProgress,
3824                        void * pProgressArg )
3825 {
3826     OGRErr ret = OGRERR_NONE;
3827     OGRFeatureDefn *poDefnInput = GetLayerDefn();
3828     OGRFeatureDefn *poDefnResult = nullptr;
3829     OGRGeometry *pGeometryMethodFilter = nullptr;
3830     int *mapInput = nullptr;
3831     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
3832     double progress_counter = 0;
3833     double progress_ticker = 0;
3834     int bSkipFailures = CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
3835     int bPromoteToMulti = CPLTestBool(CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
3836 
3837     // check for GEOS
3838     if (!OGRGeometryFactory::haveGEOS()) {
3839         return OGRERR_UNSUPPORTED_OPERATION;
3840     }
3841 
3842     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
3843     if (ret != OGRERR_NONE) goto done;
3844     ret = create_field_map(poDefnInput, &mapInput);
3845     if (ret != OGRERR_NONE) goto done;
3846     ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput, nullptr, false, papszOptions);
3847     if (ret != OGRERR_NONE) goto done;
3848 
3849     poDefnResult = pLayerResult->GetLayerDefn();
3850     for( auto&& x: this ) {
3851 
3852         if (pfnProgress) {
3853             double p = progress_counter/progress_max;
3854             if (p > progress_ticker) {
3855                 if (!pfnProgress(p, "", pProgressArg)) {
3856                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3857                     ret = OGRERR_FAILURE;
3858                     goto done;
3859                 }
3860             }
3861             progress_counter += 1.0;
3862         }
3863 
3864         // set up the filter on method layer
3865         CPLErrorReset();
3866         OGRGeometry *x_geom = set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
3867         if (CPLGetLastErrorType() != CE_None) {
3868             if (!bSkipFailures) {
3869                 ret = OGRERR_FAILURE;
3870                 goto done;
3871             } else {
3872                 CPLErrorReset();
3873                 ret = OGRERR_NONE;
3874             }
3875         }
3876         if (!x_geom) {
3877             continue;
3878         }
3879 
3880         OGRGeometryUniquePtr geom; // this will be the geometry of the result feature
3881         // incrementally add area from y to geom
3882         for( auto&& y: pLayerMethod ) {
3883             OGRGeometry *y_geom = y->GetGeometryRef();
3884             if (!y_geom) continue;
3885             if (!geom) {
3886                 geom.reset(y_geom->clone());
3887             } else {
3888                 CPLErrorReset();
3889                 OGRGeometryUniquePtr geom_new(geom->Union(y_geom));
3890                 if (CPLGetLastErrorType() != CE_None || geom_new == nullptr) {
3891                     if (!bSkipFailures) {
3892                         ret = OGRERR_FAILURE;
3893                         goto done;
3894                     } else {
3895                         CPLErrorReset();
3896                         ret = OGRERR_NONE;
3897                     }
3898                 } else {
3899                     geom.swap(geom_new);
3900                 }
3901             }
3902         }
3903 
3904         // possibly add a new feature with area x intersection sum of y
3905         if (geom) {
3906             CPLErrorReset();
3907             OGRGeometryUniquePtr poIntersection(x_geom->Intersection(geom.get()));
3908             if (CPLGetLastErrorType() != CE_None || poIntersection == nullptr) {
3909                 if (!bSkipFailures) {
3910                     ret = OGRERR_FAILURE;
3911                     goto done;
3912                 } else {
3913                     CPLErrorReset();
3914                     ret = OGRERR_NONE;
3915                 }
3916             }
3917             else if( !poIntersection->IsEmpty() )
3918             {
3919                 OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
3920                 z->SetFieldsFrom(x.get(), mapInput);
3921                 if( bPromoteToMulti )
3922                     poIntersection.reset(promote_to_multi(poIntersection.release()));
3923                 z->SetGeometryDirectly(poIntersection.release());
3924                 ret = pLayerResult->CreateFeature(z.get());
3925                 if (ret != OGRERR_NONE) {
3926                     if (!bSkipFailures) {
3927                         goto done;
3928                     } else {
3929                         CPLErrorReset();
3930                         ret = OGRERR_NONE;
3931                     }
3932                 }
3933             }
3934         }
3935     }
3936     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg)) {
3937       CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
3938       ret = OGRERR_FAILURE;
3939       goto done;
3940     }
3941 done:
3942     // release resources
3943     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
3944     if (pGeometryMethodFilter) delete pGeometryMethodFilter;
3945     if (mapInput) VSIFree(mapInput);
3946     return ret;
3947 }
3948 
3949 /************************************************************************/
3950 /*                           OGR_L_Clip()                               */
3951 /************************************************************************/
3952 
3953 /**
3954  * \brief Clip off areas that are not covered by the method layer.
3955  *
3956  * The result layer contains features whose geometries represent areas
3957  * that are in the input layer and in the method layer. The features
3958  * in the result layer have the (possibly clipped) areas of features
3959  * in the input layer and the attributes from the same features. The
3960  * schema of the result layer can be set by the user or, if it is
3961  * empty, is initialized to contain all fields in the input layer.
3962  *
3963  * \note For best performance use the minimum amount of features in
3964  * the method layer and copy it into a memory layer.
3965  *
3966  * \note This method relies on GEOS support. Do not use unless the
3967  * GEOS support is compiled in.
3968  *
3969  * The recognized list of options is :
3970  * <ul>
3971  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
3972  *     feature could not be inserted or a GEOS call failed.
3973  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
3974  *     into MultiPolygons, or LineStrings to MultiLineStrings.
3975  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
3976  *     will be created from the fields of the input layer.
3977  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
3978  *     will be created from the fields of the method layer.
3979  * </ul>
3980  *
3981  * This function is the same as the C++ method OGRLayer::Clip().
3982  *
3983  * @param pLayerInput the input layer. Should not be NULL.
3984  *
3985  * @param pLayerMethod the method layer. Should not be NULL.
3986  *
3987  * @param pLayerResult the layer where the features resulting from the
3988  * operation are inserted. Should not be NULL. See above the note
3989  * about the schema.
3990  *
3991  * @param papszOptions NULL terminated list of options (may be NULL).
3992  *
3993  * @param pfnProgress a GDALProgressFunc() compatible callback function for
3994  * reporting progress or NULL.
3995  *
3996  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
3997  *
3998  * @return an error code if there was an error or the execution was
3999  * interrupted, OGRERR_NONE otherwise.
4000  *
4001  * @note The first geometry field is always used.
4002  *
4003  * @since OGR 1.10
4004  */
4005 
OGR_L_Clip(OGRLayerH pLayerInput,OGRLayerH pLayerMethod,OGRLayerH pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)4006 OGRErr OGR_L_Clip( OGRLayerH pLayerInput,
4007                    OGRLayerH pLayerMethod,
4008                    OGRLayerH pLayerResult,
4009                    char** papszOptions,
4010                    GDALProgressFunc pfnProgress,
4011                    void * pProgressArg )
4012 
4013 {
4014     VALIDATE_POINTER1( pLayerInput, "OGR_L_Clip", OGRERR_INVALID_HANDLE );
4015     VALIDATE_POINTER1( pLayerMethod, "OGR_L_Clip", OGRERR_INVALID_HANDLE );
4016     VALIDATE_POINTER1( pLayerResult, "OGR_L_Clip", OGRERR_INVALID_HANDLE );
4017 
4018     return OGRLayer::FromHandle(pLayerInput)->Clip(
4019         OGRLayer::FromHandle(pLayerMethod),
4020         OGRLayer::FromHandle(pLayerResult),
4021         papszOptions, pfnProgress, pProgressArg );
4022 }
4023 
4024 /************************************************************************/
4025 /*                              Erase()                                 */
4026 /************************************************************************/
4027 
4028 /**
4029  * \brief Remove areas that are covered by the method layer.
4030  *
4031  * The result layer contains features whose geometries represent areas
4032  * that are in the input layer but not in the method layer. The
4033  * features in the result layer have attributes from the input
4034  * layer. The schema of the result layer can be set by the user or, if
4035  * it is empty, is initialized to contain all fields in the input
4036  * layer.
4037  *
4038  * \note For best performance use the minimum amount of features in
4039  * the method layer and copy it into a memory layer.
4040  *
4041  * \note This method relies on GEOS support. Do not use unless the
4042  * GEOS support is compiled in.
4043  *
4044  * The recognized list of options is :
4045  * <ul>
4046  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4047  *     feature could not be inserted or a GEOS call failed.
4048  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
4049  *     into MultiPolygons, or LineStrings to MultiLineStrings.
4050  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4051  *     will be created from the fields of the input layer.
4052  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4053  *     will be created from the fields of the method layer.
4054  * </ul>
4055  *
4056  * This method is the same as the C function OGR_L_Erase().
4057  *
4058  * @param pLayerMethod the method layer. Should not be NULL.
4059  *
4060  * @param pLayerResult the layer where the features resulting from the
4061  * operation are inserted. Should not be NULL. See above the note
4062  * about the schema.
4063  *
4064  * @param papszOptions NULL terminated list of options (may be NULL).
4065  *
4066  * @param pfnProgress a GDALProgressFunc() compatible callback function for
4067  * reporting progress or NULL.
4068  *
4069  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4070  *
4071  * @return an error code if there was an error or the execution was
4072  * interrupted, OGRERR_NONE otherwise.
4073  *
4074  * @note The first geometry field is always used.
4075  *
4076  * @since OGR 1.10
4077  */
4078 
Erase(OGRLayer * pLayerMethod,OGRLayer * pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)4079 OGRErr OGRLayer::Erase( OGRLayer *pLayerMethod,
4080                         OGRLayer *pLayerResult,
4081                         char** papszOptions,
4082                         GDALProgressFunc pfnProgress,
4083                         void * pProgressArg )
4084 {
4085     OGRErr ret = OGRERR_NONE;
4086     OGRFeatureDefn *poDefnInput = GetLayerDefn();
4087     OGRFeatureDefn *poDefnResult = nullptr;
4088     OGRGeometry *pGeometryMethodFilter = nullptr;
4089     int *mapInput = nullptr;
4090     double progress_max = static_cast<double>(GetFeatureCount(FALSE));
4091     double progress_counter = 0;
4092     double progress_ticker = 0;
4093     int bSkipFailures = CPLTestBool(CSLFetchNameValueDef(papszOptions, "SKIP_FAILURES", "NO"));
4094     int bPromoteToMulti = CPLTestBool(CSLFetchNameValueDef(papszOptions, "PROMOTE_TO_MULTI", "NO"));
4095 
4096     // check for GEOS
4097     if (!OGRGeometryFactory::haveGEOS()) {
4098         return OGRERR_UNSUPPORTED_OPERATION;
4099     }
4100 
4101     // get resources
4102     ret = clone_spatial_filter(pLayerMethod, &pGeometryMethodFilter);
4103     if (ret != OGRERR_NONE) goto done;
4104     ret = create_field_map(poDefnInput, &mapInput);
4105     if (ret != OGRERR_NONE) goto done;
4106     ret = set_result_schema(pLayerResult, poDefnInput, nullptr, mapInput, nullptr, false, papszOptions);
4107     if (ret != OGRERR_NONE) goto done;
4108     poDefnResult = pLayerResult->GetLayerDefn();
4109 
4110     for( auto&& x: this ) {
4111 
4112         if (pfnProgress) {
4113             double p = progress_counter/progress_max;
4114             if (p > progress_ticker) {
4115                 if (!pfnProgress(p, "", pProgressArg)) {
4116                     CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4117                     ret = OGRERR_FAILURE;
4118                     goto done;
4119                 }
4120             }
4121             progress_counter += 1.0;
4122         }
4123 
4124         // set up the filter on the method layer
4125         CPLErrorReset();
4126         OGRGeometry *x_geom = set_filter_from(pLayerMethod, pGeometryMethodFilter, x.get());
4127         if (CPLGetLastErrorType() != CE_None) {
4128             if (!bSkipFailures) {
4129                 ret = OGRERR_FAILURE;
4130                 goto done;
4131             } else {
4132                 CPLErrorReset();
4133                 ret = OGRERR_NONE;
4134             }
4135         }
4136         if (!x_geom) {
4137             continue;
4138         }
4139 
4140         OGRGeometryUniquePtr geom(x_geom->clone()); // this will be the geometry of the result feature
4141         // incrementally erase y from geom
4142         for( auto&& y: pLayerMethod ) {
4143             OGRGeometry *y_geom = y->GetGeometryRef();
4144             if (!y_geom) continue;
4145             CPLErrorReset();
4146             OGRGeometryUniquePtr geom_new(geom->Difference(y_geom));
4147             if (CPLGetLastErrorType() != CE_None || geom_new == nullptr) {
4148                 if (!bSkipFailures) {
4149                     ret = OGRERR_FAILURE;
4150                     goto done;
4151                 } else {
4152                     CPLErrorReset();
4153                     ret = OGRERR_NONE;
4154                 }
4155             } else {
4156                 geom.swap(geom_new);
4157                 if (geom->IsEmpty())
4158                 {
4159                     break;
4160                 }
4161             }
4162         }
4163 
4164         // add a new feature if there is remaining area
4165         if (!geom->IsEmpty()) {
4166             OGRFeatureUniquePtr z(new OGRFeature(poDefnResult));
4167             z->SetFieldsFrom(x.get(), mapInput);
4168             if( bPromoteToMulti )
4169                 geom.reset(promote_to_multi(geom.release()));
4170             z->SetGeometryDirectly(geom.release());
4171             ret = pLayerResult->CreateFeature(z.get());
4172             if (ret != OGRERR_NONE) {
4173                 if (!bSkipFailures) {
4174                     goto done;
4175                 } else {
4176                     CPLErrorReset();
4177                     ret = OGRERR_NONE;
4178                 }
4179             }
4180         }
4181     }
4182     if (pfnProgress && !pfnProgress(1.0, "", pProgressArg)) {
4183       CPLError(CE_Failure, CPLE_UserInterrupt, "User terminated");
4184       ret = OGRERR_FAILURE;
4185       goto done;
4186     }
4187 done:
4188     // release resources
4189     pLayerMethod->SetSpatialFilter(pGeometryMethodFilter);
4190     if (pGeometryMethodFilter) delete pGeometryMethodFilter;
4191     if (mapInput) VSIFree(mapInput);
4192     return ret;
4193 }
4194 
4195 /************************************************************************/
4196 /*                           OGR_L_Erase()                              */
4197 /************************************************************************/
4198 
4199 /**
4200  * \brief Remove areas that are covered by the method layer.
4201  *
4202  * The result layer contains features whose geometries represent areas
4203  * that are in the input layer but not in the method layer. The
4204  * features in the result layer have attributes from the input
4205  * layer. The schema of the result layer can be set by the user or, if
4206  * it is empty, is initialized to contain all fields in the input
4207  * layer.
4208  *
4209  * \note For best performance use the minimum amount of features in
4210  * the method layer and copy it into a memory layer.
4211  *
4212  * \note This method relies on GEOS support. Do not use unless the
4213  * GEOS support is compiled in.
4214  *
4215  * The recognized list of options is :
4216  * <ul>
4217  * <li>SKIP_FAILURES=YES/NO. Set it to YES to go on, even when a
4218  *     feature could not be inserted or a GEOS call failed.
4219  * <li>PROMOTE_TO_MULTI=YES/NO. Set it to YES to convert Polygons
4220  *     into MultiPolygons, or LineStrings to MultiLineStrings.
4221  * <li>INPUT_PREFIX=string. Set a prefix for the field names that
4222  *     will be created from the fields of the input layer.
4223  * <li>METHOD_PREFIX=string. Set a prefix for the field names that
4224  *     will be created from the fields of the method layer.
4225  * </ul>
4226  *
4227  * This function is the same as the C++ method OGRLayer::Erase().
4228  *
4229  * @param pLayerInput the input layer. Should not be NULL.
4230  *
4231  * @param pLayerMethod the method layer. Should not be NULL.
4232  *
4233  * @param pLayerResult the layer where the features resulting from the
4234  * operation are inserted. Should not be NULL. See above the note
4235  * about the schema.
4236  *
4237  * @param papszOptions NULL terminated list of options (may be NULL).
4238  *
4239  * @param pfnProgress a GDALProgressFunc() compatible callback function for
4240  * reporting progress or NULL.
4241  *
4242  * @param pProgressArg argument to be passed to pfnProgress. May be NULL.
4243  *
4244  * @return an error code if there was an error or the execution was
4245  * interrupted, OGRERR_NONE otherwise.
4246  *
4247  * @note The first geometry field is always used.
4248  *
4249  * @since OGR 1.10
4250  */
4251 
OGR_L_Erase(OGRLayerH pLayerInput,OGRLayerH pLayerMethod,OGRLayerH pLayerResult,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressArg)4252 OGRErr OGR_L_Erase( OGRLayerH pLayerInput,
4253                     OGRLayerH pLayerMethod,
4254                     OGRLayerH pLayerResult,
4255                     char** papszOptions,
4256                     GDALProgressFunc pfnProgress,
4257                     void * pProgressArg )
4258 
4259 {
4260     VALIDATE_POINTER1( pLayerInput, "OGR_L_Erase", OGRERR_INVALID_HANDLE );
4261     VALIDATE_POINTER1( pLayerMethod, "OGR_L_Erase", OGRERR_INVALID_HANDLE );
4262     VALIDATE_POINTER1( pLayerResult, "OGR_L_Erase", OGRERR_INVALID_HANDLE );
4263 
4264     return OGRLayer::FromHandle(pLayerInput)->Erase(
4265         OGRLayer::FromHandle(pLayerMethod),
4266         OGRLayer::FromHandle(pLayerResult),
4267         papszOptions, pfnProgress, pProgressArg );
4268 }
4269 
4270 /************************************************************************/
4271 /*                  OGRLayer::FeatureIterator::Private                  */
4272 /************************************************************************/
4273 
4274 struct OGRLayer::FeatureIterator::Private
4275 {
4276     CPL_DISALLOW_COPY_ASSIGN(Private)
4277     Private() = default;
4278 
4279     OGRFeatureUniquePtr m_poFeature{};
4280     OGRLayer* m_poLayer = nullptr;
4281     bool m_bError = false;
4282     bool m_bEOF = true;
4283 };
4284 
4285 /************************************************************************/
4286 /*                OGRLayer::FeatureIterator::FeatureIterator()          */
4287 /************************************************************************/
4288 
FeatureIterator(OGRLayer * poLayer,bool bStart)4289 OGRLayer::FeatureIterator::FeatureIterator(OGRLayer* poLayer, bool bStart):
4290     m_poPrivate(new OGRLayer::FeatureIterator::Private())
4291 {
4292     m_poPrivate->m_poLayer = poLayer;
4293     if( bStart )
4294     {
4295         if( m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator )
4296         {
4297             CPLError(CE_Failure, CPLE_NotSupported,
4298                         "Only one feature iterator can be "
4299                         "active at a time");
4300             m_poPrivate->m_bError = true;
4301         }
4302         else
4303         {
4304             m_poPrivate->m_poLayer->ResetReading();
4305             m_poPrivate->m_poFeature.reset(m_poPrivate->m_poLayer->GetNextFeature());
4306             m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
4307             m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = true;
4308         }
4309     }
4310 }
4311 
4312 /************************************************************************/
4313 /*               ~OGRLayer::FeatureIterator::FeatureIterator()          */
4314 /************************************************************************/
4315 
~FeatureIterator()4316 OGRLayer::FeatureIterator::~FeatureIterator()
4317 {
4318     if( !m_poPrivate->m_bError && m_poPrivate->m_poLayer)
4319         m_poPrivate->m_poLayer->m_poPrivate->m_bInFeatureIterator = false;
4320 }
4321 
4322 /************************************************************************/
4323 /*                              operator*()                             */
4324 /************************************************************************/
4325 
operator *()4326 OGRFeatureUniquePtr& OGRLayer::FeatureIterator::operator*()
4327 {
4328     return m_poPrivate->m_poFeature;
4329 }
4330 
4331 /************************************************************************/
4332 /*                              operator++()                            */
4333 /************************************************************************/
4334 
operator ++()4335 OGRLayer::FeatureIterator& OGRLayer::FeatureIterator::operator++()
4336 {
4337     m_poPrivate->m_poFeature.reset(m_poPrivate-> m_poLayer->GetNextFeature());
4338     m_poPrivate->m_bEOF = m_poPrivate->m_poFeature == nullptr;
4339     return *this;
4340 }
4341 
4342 /************************************************************************/
4343 /*                             operator!=()                             */
4344 /************************************************************************/
4345 
operator !=(const OGRLayer::FeatureIterator & it) const4346 bool OGRLayer::FeatureIterator::operator!=(const OGRLayer::FeatureIterator& it) const
4347 {
4348     return m_poPrivate->m_bEOF != it.m_poPrivate->m_bEOF;
4349 }
4350 
4351 /************************************************************************/
4352 /*                                 begin()                              */
4353 /************************************************************************/
4354 
begin()4355 OGRLayer::FeatureIterator OGRLayer::begin()
4356 {
4357     return {this, true};
4358 }
4359 
4360 /************************************************************************/
4361 /*                                  end()                               */
4362 /************************************************************************/
4363 
end()4364 OGRLayer::FeatureIterator OGRLayer::end()
4365 {
4366     return {this, false};
4367 }
4368