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