-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathfeaturelayer.jl
1544 lines (1299 loc) · 57.6 KB
/
featurelayer.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
function destroy(layer::AbstractFeatureLayer)::Nothing
layer.ptr = C_NULL
return nothing
end
function destroy(layer::IFeatureLayer)::Nothing
layer.ptr = C_NULL
layer.ownedby = Dataset()
layer.spatialref = SpatialRef()
return nothing
end
"""
createlayer(name, dataset, geom, spatialref, options)
This function attempts to create a new layer on the dataset with the indicated
`name`, `spatialref`, and geometry type.
### Keyword Arguments
* `name`: the name for the new layer. This should ideally not match any
existing layer on the datasource. Defaults to an empty string.
* `dataset`: the dataset. Defaults to creating a new in memory dataset.
* `geom`: the geometry type for the layer. Use `wkbUnknown` (default) if
there are no constraints on the types geometry to be written.
* `spatialref`: the coordinate system to use for the new layer.
* `options`: a StringList of name=value (driver-specific) options.
"""
function createlayer(;
name::AbstractString = "",
dataset::AbstractDataset = create(getdriver("Memory")),
geom::OGRwkbGeometryType = wkbUnknown,
spatialref::AbstractSpatialRef = SpatialRef(),
options = StringList(C_NULL),
)::IFeatureLayer
return IFeatureLayer(
GDAL.gdaldatasetcreatelayer(dataset, name, spatialref, geom, options),
ownedby = dataset,
spatialref = spatialref,
)
end
function unsafe_createlayer(;
name::AbstractString = "",
dataset::AbstractDataset = create(getdriver("Memory")),
geom::OGRwkbGeometryType = wkbUnknown,
spatialref::AbstractSpatialRef = SpatialRef(),
options = StringList(C_NULL),
)::FeatureLayer
return FeatureLayer(
GDAL.gdaldatasetcreatelayer(dataset, name, spatialref, geom, options),
ownedby = dataset,
spatialref = spatialref,
)
end
"""
copy(layer, dataset, name, options)
Copy an existing layer.
This method creates a new layer, duplicate the field definitions of the source
layer, and then duplicates each feature of the source layer.
### Parameters
* `layer`: source layer to be copied.
### Keyword Arguments
* `dataset`: the dataset handle. (Creates a new dataset in memory by default.)
* `name`: the name of the layer to create on the dataset.
* `options`: a StringList of name=value (driver-specific) options.
"""
function copy(
layer::AbstractFeatureLayer;
dataset::AbstractDataset = create(getdriver("Memory")),
name::AbstractString = "copy($(getname(layer)))",
options = StringList(C_NULL),
)::IFeatureLayer
return IFeatureLayer(
GDAL.gdaldatasetcopylayer(dataset, layer, name, options),
ownedby = dataset,
)
end
function unsafe_copy(
layer::AbstractFeatureLayer;
dataset::AbstractDataset = create(getdriver("Memory")),
name::AbstractString = "copy($(getname(layer)))",
options = StringList(C_NULL),
)::FeatureLayer
return FeatureLayer(
GDAL.gdaldatasetcopylayer(dataset, layer, name, options),
)
end
"""
getname(layer::AbstractFeatureLayer)
Return the layer name.
"""
getname(layer::AbstractFeatureLayer)::String = GDAL.ogr_l_getname(layer)
"""
getgeomtype(layer::AbstractFeatureLayer)
Return the layer geometry type.
"""
getgeomtype(layer::AbstractFeatureLayer)::OGRwkbGeometryType =
GDAL.ogr_l_getgeomtype(layer)
"""
getspatialfilter(layer::AbstractFeatureLayer)
Returns the current spatial filter for this layer.
"""
function getspatialfilter(layer::AbstractFeatureLayer)::IGeometry
result = GDAL.ogr_l_getspatialfilter(layer)
return if result == C_NULL
IGeometry(result)
else
# NOTE(yeesian): we make a clone here so that the geometry does not
# depend on the FeatureLayer.
IGeometry(GDAL.ogr_g_clone(result))
end
end
"""
getspatialref(layer::AbstractFeatureLayer)
Returns a clone of the spatial reference system for this layer.
"""
function getspatialref(layer::AbstractFeatureLayer)::ISpatialRef
result = GDAL.ogr_l_getspatialref(layer)
return if result == C_NULL
ISpatialRef()
else
# NOTE(yeesian): we make a clone here so that the spatialref does not
# depend on the FeatureLayer/Dataset.
ISpatialRef(GDAL.osrclone(result))
end
end
function unsafe_getspatialref(layer::AbstractFeatureLayer)::SpatialRef
result = GDAL.ogr_l_getspatialref(layer)
return if result == C_NULL
SpatialRef()
else
# NOTE(yeesian): we make a clone here so that the spatialref does not
# depend on the FeatureLayer/Dataset.
SpatialRef(GDAL.osrclone(result))
end
end
"""
setspatialfilter!(layer::AbstractFeatureLayer, geom::AbstractGeometry)
Set a new spatial filter for the layer, using the geom.
This method set the geometry to be used as a spatial filter when fetching
features via the `nextfeature()` method. Only features that geometrically
intersect the filter geometry will be returned.
### Parameters
* `layer` handle to the layer on which to set the spatial filter.
* `geom` handle to the geometry to use as a filtering region. NULL may be
passed indicating that the current spatial filter should be cleared,
but no new one instituted.
### Remarks
Currently this test may be inaccurately implemented, but it is guaranteed
that all features whose envelope (as returned by OGRGeometry::getEnvelope())
overlaps the envelope of the spatial filter will be returned. This can result
in more shapes being returned that should strictly be the case.
For the time being the passed filter geometry should be in the same SRS as the
geometry field definition it corresponds to (as returned by
`GetLayerDefn()->OGRFeatureDefn::GetGeomFieldDefn(i)->GetSpatialRef()`).
In the future this may be generalized.
Note that only the last spatial filter set is applied, even if several
successive calls are done with different iGeomField values.
"""
function setspatialfilter!(
layer::L,
geom::AbstractGeometry,
)::L where {L<:AbstractFeatureLayer}
# This method makes an internal copy of `geom`. The input `geom` remains
# the responsibility of the caller, and may be safely destroyed.
GDAL.ogr_l_setspatialfilter(layer, geom)
return layer
end
function clearspatialfilter!(layer::L)::L where {L<:AbstractFeatureLayer}
GDAL.ogr_l_setspatialfilter(layer, C_NULL)
return layer
end
"""
setspatialfilter!(layer::AbstractFeatureLayer, xmin, ymin, xmax, ymax)
Set a new rectangular spatial filter for the layer.
This method set rectangle to be used as a spatial filter when fetching features
via the `nextfeature()` method. Only features that geometrically intersect the
given rectangle will be returned.
The x/y values should be in the same coordinate system as the layer as a whole
(as returned by OGRLayer::GetSpatialRef()). Internally this method is normally
implemented as creating a 5 vertex closed rectangular polygon and passing it to
OGRLayer::SetSpatialFilter(). It exists as a convenience.
The only way to clear a spatial filter set with this method is to call
`OGRLayer::SetSpatialFilter(NULL)`.
"""
function setspatialfilter!(
layer::L,
xmin::Real,
ymin::Real,
xmax::Real,
ymax::Real,
)::L where {L<:AbstractFeatureLayer}
GDAL.ogr_l_setspatialfilterrect(layer, xmin, ymin, xmax, ymax)
return layer
end
"""
setspatialfilter!(layer::AbstractFeatureLayer, i::Integer,
geom::AbstractGeometry)
Set a new spatial filter.
This method set the geometry to be used as a spatial filter when fetching
features via the `nextfeature()` method. Only features that geometrically
intersect the filter geometry will be returned.
### Parameters
* `layer`: the layer on which to set the spatial filter.
* `i`: index of the geometry field on which the spatial filter operates.
* `geom`: the geometry to use as a filtering region. NULL may be passed
indicating that the current spatial filter should be cleared, but
no new one instituted.
### Remarks
Currently this test is may be inaccurately implemented, but it is guaranteed
that all features who's envelope (as returned by OGRGeometry::getEnvelope())
overlaps the envelope of the spatial filter will be returned. This can result
in more shapes being returned that should strictly be the case.
For the time being the passed filter geometry should be in the same SRS as the
layer (as returned by OGRLayer::GetSpatialRef()). In the future this may be
generalized.
"""
function setspatialfilter!(
layer::L,
i::Integer,
geom::AbstractGeometry,
)::L where {L<:AbstractFeatureLayer}
# This method makes an internal copy of `geom`. The input `geom` remains
# the responsibility of the caller, and may be safely destroyed.
GDAL.ogr_l_setspatialfilterex(layer, i, geom)
return layer
end
function clearspatialfilter!(
layer::L,
i::Integer,
)::L where {L<:AbstractFeatureLayer}
GDAL.ogr_l_setspatialfilterex(layer, i, C_NULL)
return layer
end
"""
setspatialfilter!(layer::AbstractFeatureLayer, i::Integer, xmin, ymin, xmax,
ymax)
Set a new rectangular spatial filter.
### Parameters
* `layer`: the feature layer on which to set the spatial filter.
* `i`: index of the geometry field on which the spatial filter operates.
* `xmin`: the minimum X coordinate for the rectangular region.
* `ymin`: the minimum Y coordinate for the rectangular region.
* `xmax`: the maximum X coordinate for the rectangular region.
* `ymax`: the maximum Y coordinate for the rectangular region.
"""
function setspatialfilter!(
layer::L,
i::Integer,
xmin::Real,
ymin::Real,
xmax::Real,
ymax::Real,
)::L where {L<:AbstractFeatureLayer}
GDAL.ogr_l_setspatialfilterrectex(layer, i, xmin, ymin, xmax, ymax)
return layer
end
"""
setattributefilter!(layer::AbstractFeatureLayer, query::AbstractString)
Set a new attribute query.
This method sets the attribute query string to be used when fetching features
via the `nextfeature()` method. Only features for which the query evaluates as
`true` will be returned.
### Parameters
* `layer`: handle to the layer on which attribute query will be executed.
* `query`: query in restricted SQL WHERE format.
### Remarks
The query string should be in the format of an SQL WHERE clause. For instance
`"population > 1000000 and population < 5000000"` where population is an
attribute in the layer. The query format is normally a restricted form of
SQL WHERE clause as described in the "WHERE" section of the OGR SQL tutorial.
In some cases (RDBMS backed drivers) the native capabilities of the database may
be used to interpret the WHERE clause in which case the capabilities will be
broader than those of OGR SQL.
Note that installing a query string will generally result in resetting the
current reading position (ala `resetreading!()`).
"""
function setattributefilter!(
layer::L,
query::AbstractString,
)::L where {L<:AbstractFeatureLayer}
result = GDAL.ogr_l_setattributefilter(layer, query)
@ogrerr result """Failed to set a new attribute query. The query expression
might be in error."""
return layer
end
function clearattributefilter!(layer::L)::L where {L<:AbstractFeatureLayer}
result = GDAL.ogr_l_setattributefilter(layer, C_NULL)
@ogrerr result "OGRErr $result: Failed to clear attribute query."
return layer
end
"""
resetreading!(layer::AbstractFeatureLayer)
Reset feature reading to start on the first feature.
This affects `nextfeature()`.
"""
function resetreading!(layer::L)::L where {L<:AbstractFeatureLayer}
GDAL.ogr_l_resetreading(layer)
return layer
end
"""
unsafe_nextfeature(layer::AbstractFeatureLayer)
Fetch the next available feature from this layer.
### Parameters
* `layer`: the feature layer to be read from.
### Remarks
This method implements sequential access to the features of a layer. The
`resetreading!()` method can be used to start at the beginning again. Only
features matching the current spatial filter (set with `setspatialfilter!()`)
will be returned.
The returned feature becomes the responsibility of the caller to delete with
`destroy()`. It is critical that all features associated with a `FeatureLayer`
(more specifically a `FeatureDefn`) be destroyed before that layer is destroyed.
Features returned by `nextfeature()` may or may not be affected by concurrent
modifications depending on drivers. A guaranteed way of seeing modifications in
effect is to call `resetreading!()` on layers where `nextfeature()` has been
called, before reading again. Structural changes in layers (field addition,
deletion, ...) when a read is in progress may or may not be possible depending
on drivers. If a transaction is committed/aborted, the current sequential
reading may or may not be valid after that operation and a call to
`resetreading!()` might be needed.
"""
function unsafe_nextfeature(layer::AbstractFeatureLayer)::Feature
return Feature(GDAL.ogr_l_getnextfeature(layer))
end
"""
setnextbyindex!(layer::AbstractFeatureLayer, i::Integer)
Move read cursor to the `i`-th feature in the current resultset.
This method allows positioning of a layer such that the `nextfeature()` call
will read the requested feature, where `i` is an absolute index into the
current result set. So, setting it to `3` would mean the next feature read with
`nextfeature()` would have been the fourth feature to have been read if
sequential reading took place from the beginning of the layer, including
accounting for spatial and attribute filters.
### Parameters
* `layer`: handle to the layer
* `i`: the index indicating how many steps into the result set to seek.
### Remarks
Only in rare circumstances is `setnextbyindex!()` efficiently implemented. In
all other cases the default implementation which calls `resetreading!()` and
then calls `nextfeature()` `i` times is used. To determine if fast seeking is
available on the layer, use the `testcapability()` method with a value of
`OLCFastSetNextByIndex`.
"""
function setnextbyindex!(
layer::L,
i::Integer,
)::L where {L<:AbstractFeatureLayer}
result = GDAL.ogr_l_setnextbyindex(layer, i)
@ogrerr result "Failed to move the cursor to index $i"
return layer
end
"""
unsafe_getfeature(layer::AbstractFeatureLayer, i::Integer)
Return a feature (now owned by the caller) by its identifier or NULL on failure.
### Parameters
* `layer`: the feature layer to be read from.
* `i`: the index of the feature to be returned.
### Remarks
This function will attempt to read the identified feature. The nFID value cannot
be OGRNullFID. Success or failure of this operation is unaffected by the spatial
or attribute filters (and specialized implementations in drivers should make
sure that they do not take into account spatial or attribute filters).
If this function returns a non-NULL feature, it is guaranteed that its feature
id (OGR_F_GetFID()) will be the same as nFID.
Use OGR_L_TestCapability(OLCRandomRead) to establish if this layer supports
efficient random access reading via OGR_L_GetFeature(); however, the call should
always work if the feature exists as a fallback implementation just scans all
the features in the layer looking for the desired feature.
Sequential reads (with OGR_L_GetNextFeature()) are generally considered
interrupted by a OGR_L_GetFeature() call.
The returned feature is now owned by the caller, and should be freed with
`destroy()`.
"""
unsafe_getfeature(layer::AbstractFeatureLayer, i::Integer)::Feature =
Feature(GDAL.ogr_l_getfeature(layer, i))
"""
setfeature!(layer::AbstractFeatureLayer, feature::AbstractFeature)
Rewrite an existing feature.
This function will write a feature to the layer, based on the feature id within
the OGRFeature.
### Remarks
Use OGR_L_TestCapability(OLCRandomWrite) to establish if this layer supports
random access writing via OGR_L_SetFeature().
"""
function setfeature!(layer::AbstractFeatureLayer, feature::AbstractFeature)
result = GDAL.ogr_l_setfeature(layer, feature)
# OGRERR_NONE if the operation works, otherwise an appropriate error code
# (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
@ogrerr result "Failed to set feature."
return layer
end
"""
addfeature!(layer::AbstractFeatureLayer, feature::AbstractFeature)
Write a new feature within a layer.
### Remarks
The passed feature is written to the layer as a new feature, rather than
overwriting an existing one. If the feature has a feature id other than
OGRNullFID, then the native implementation may use that as the feature id of
the new feature, but not necessarily. Upon successful return the passed feature
will have been updated with the new feature id.
"""
function addfeature!(
layer::L,
feature::AbstractFeature,
)::L where {L<:AbstractFeatureLayer}
result = GDAL.ogr_l_createfeature(layer, feature)
@ogrerr result "Failed to create and write feature in layer."
return layer
end
function addfeature(f::Function, layer::L)::L where {L<:AbstractFeatureLayer}
feature = unsafe_createfeature(layer)
return try
f(feature)
addfeature!(layer, feature)
finally
destroy(feature)
end
end
"""
unsafe_createfeature(layer::AbstractFeatureLayer)
Create and returns a new feature based on the layer definition.
The newly feature is owned by the layer (it will increase the number of features
the layer by one), but the feature has not been written to the layer yet.
"""
unsafe_createfeature(layer::AbstractFeatureLayer)::Feature =
unsafe_createfeature(layerdefn(layer))
function createfeature(f::Function, layer::L)::L where {L<:AbstractFeatureLayer}
feature = unsafe_createfeature(layer)
return try
f(feature)
setfeature!(layer, feature)
finally
destroy(feature)
end
end
"""
deletefeature!(layer::AbstractFeatureLayer, i::Integer)
Delete feature with fid `i` from layer.
### Remarks
The feature with the indicated feature id is deleted from the layer if supported
by the driver. Most drivers do not support feature deletion, and will return
OGRERR_UNSUPPORTED_OPERATION. The OGR_L_TestCapability() function may be called
with OLCDeleteFeature to check if the driver supports feature deletion.
"""
function deletefeature!(layer::L, i::Integer)::L where {L<:AbstractFeatureLayer}
result = GDAL.ogr_l_deletefeature(layer, i)
# OGRERR_NONE if the operation works, otherwise an appropriate error code
# (e.g OGRERR_NON_EXISTING_FEATURE if the feature does not exist).
@ogrerr result "OGRErr $result: Failed to delete feature $i"
return layer
end
"""
layerdefn(layer::AbstractFeatureLayer)
Returns a view of the schema information for this layer.
### Remarks
The `featuredefn` is owned by the `layer` and should not be modified.
"""
layerdefn(layer::AbstractFeatureLayer)::IFeatureDefnView =
IFeatureDefnView(GDAL.ogr_l_getlayerdefn(layer))
"""
findfieldindex(layer::AbstractFeatureLayer,
field::Union{AbstractString, Symbol}, exactmatch::Bool)
Find the index of the field in a layer, or -1 if the field doesn't exist.
If `exactmatch` is set to `false` and the field doesn't exists in the given form
the driver might apply some changes to make it match, like those it might do if
the layer was created (eg. like `LAUNDER` in the OCI driver).
"""
function findfieldindex(
layer::AbstractFeatureLayer,
field::Union{AbstractString,Symbol},
exactmatch::Bool,
)::Integer
return GDAL.ogr_l_findfieldindex(layer, field, exactmatch)
end
"""
nfeature(layer::AbstractFeatureLayer, force::Bool = false)
Fetch the feature count in this layer, or `-1` if the count is not known.
### Parameters
* `layer`: handle to the layer that owned the features.
* `force`: flag indicating whether the count should be computed even if it is
expensive. (`false` by default.)
"""
nfeature(layer::AbstractFeatureLayer, force::Bool = false)::Integer =
GDAL.ogr_l_getfeaturecount(layer, force)
"""
ngeom(layer::AbstractFeatureLayer)
Fetch number of geometry fields on the feature layer.
"""
ngeom(layer::AbstractFeatureLayer)::Integer = ngeom(layerdefn(layer))
"""
nfield(layer::AbstractFeatureLayer)
Fetch number of fields on the feature layer.
"""
nfield(layer::AbstractFeatureLayer)::Integer = nfield(layerdefn(layer))
"""
envelope(layer::AbstractFeatureLayer, force::Bool = false)
envelope(layer::AbstractFeatureLayer, i::Integer, force::Bool = false)
Fetch the extent of this layer.
Returns the extent (MBR) of the data in the layer. If `force` is `false`, and it
would be expensive to establish the extent then OGRERR_FAILURE will be returned
indicating that the extent isn't know. If `force` is `true` then some
implementations will actually scan the entire layer once to compute the MBR of
all the features in the layer.
### Parameters
* `layer`: handle to the layer from which to get extent.
* `i`: (optional) the index of the geometry field to compute the extent.
* `force`: Flag indicating whether the extent should be computed even if it is
expensive.
### Additional Remarks
Depending on the drivers, the returned extent may or may not take the spatial
filter into account. So it is safer to call GetExtent() without setting a
spatial filter.
Layers without any geometry may return OGRERR_FAILURE just indicating that no
meaningful extents could be collected.
Note that some implementations of this method may alter the read cursor of the
layer.
"""
function envelope(
layer::AbstractFeatureLayer,
i::Integer,
force::Bool = false,
)::GDAL.OGREnvelope
envelope = Ref{GDAL.OGREnvelope}(GDAL.OGREnvelope(0, 0, 0, 0))
result = GDAL.ogr_l_getextentex(layer, i, envelope, force)
@ogrerr result "Extent not known"
return envelope[]
end
function envelope(
layer::AbstractFeatureLayer,
force::Bool = false,
)::GDAL.OGREnvelope
envelope = Ref{GDAL.OGREnvelope}(GDAL.OGREnvelope(0, 0, 0, 0))
result = GDAL.ogr_l_getextent(layer, envelope, force)
@ogrerr result "Extent not known"
return envelope[]
end
"""
testcapability(layer::AbstractFeatureLayer, capability::AbstractString)
Test if this layer supported the named capability.
### Parameters
* `capability` the name of the capability to test.
### Returns
`true` if the layer has the requested capability, `false` otherwise. It will
return `false` for any unrecognized capabilities.
### Additional Remarks
The capability codes that can be tested are represented as strings, but
`#defined` constants exists to ensure correct spelling. Specific layer types may
implement class specific capabilities, but this can't generally be discovered by
the caller.
* `OLCRandomRead` / \"RandomRead\": `true` if the GetFeature() method is
implemented in an optimized way for this layer, as opposed to the default
implementation using `resetreading!()` and `nextfeature()` to find the
requested feature id.
* `OLCSequentialWrite` / \"SequentialWrite\": `true` if the CreateFeature()
method works for this layer. Note this means that this particular layer is
writable. The same OGRLayer class may returned `false` for other layer
instances that are effectively read-only.
* `OLCRandomWrite` / \"RandomWrite\": `true` if the SetFeature() method is
operational on this layer. Note this means that this particular layer is
writable. The same OGRLayer class may returned `false` for other layer
instances that are effectively read-only.
* `OLCFastSpatialFilter` / \"FastSpatialFilter\": `true` if this layer
implements spatial filtering efficiently. Layers that effectively read all
features, and test them with the OGRFeature intersection methods should
return `false`. This can be used as a clue by the application whether it
should build and maintain its own spatial index for features in this layer.
* `OLCFastFeatureCount` / \"FastFeatureCount\": `true` if this layer can return
a feature count (via GetFeatureCount()) efficiently. i.e. without counting
the features. In some cases this will return `true` until a spatial filter
is installed after which it will return `false`.
* `OLCFastGetExtent` / \"FastGetExtent\": `true` if this layer can return its
data extent (via GetExtent()) efficiently, i.e. without scanning all the
features. In some cases this will return `true` until a spatial filter is
installed after which it will return `false`.
* `OLCFastSetNextByIndex` / \"FastSetNextByIndex\": `true` if this layer can
perform the SetNextByIndex() call efficiently, otherwise `false`.
* `OLCCreateField` / \"CreateField\": `true` if this layer can create new fields
on the current layer using CreateField(), otherwise `false`.
* `OLCCreateGeomField` / \"CreateGeomField\": (GDAL >= 1.11) `true` if this
layer can create new geometry fields on the current layer using
CreateGeomField(), otherwise `false`.
* `OLCDeleteField` / \"DeleteField\": `true` if this layer can delete existing
fields on the current layer using DeleteField(), otherwise `false`.
* `OLCReorderFields` / \"ReorderFields\": `true` if this layer can reorder
existing fields on the current layer using ReorderField() or
ReorderFields(), otherwise `false`.
* `OLCAlterFieldDefn` / \"AlterFieldDefn\": `true` if this layer can alter the
definition of an existing field on the current layer using AlterFieldDefn(),
otherwise `false`.
* `OLCDeleteFeature` / \"DeleteFeature\": `true` if the DeleteFeature() method
is supported on this layer, otherwise `false`.
* `OLCStringsAsUTF8` / \"StringsAsUTF8\": `true` if values of OFTString fields
are assured to be in UTF-8 format. If `false` the encoding of fields is
uncertain, though it might still be UTF-8.
* `OLCTransactions` / \"Transactions\": `true` if the StartTransaction(),
CommitTransaction() and RollbackTransaction() methods work in a meaningful
way, otherwise `false`.
* `OLCIgnoreFields` / \"IgnoreFields\": `true` if fields, geometry and style
will be omitted when fetching features as set by SetIgnoredFields() method.
* `OLCCurveGeometries` / \"CurveGeometries\": `true` if this layer supports
writing curve geometries or may return such geometries. (GDAL 2.0).
"""
testcapability(layer::AbstractFeatureLayer, capability::AbstractString)::Bool =
Bool(GDAL.ogr_l_testcapability(layer, capability))
function listcapability(
layer::AbstractFeatureLayer,
capabilities = (
GDAL.OLCRandomRead,
GDAL.OLCSequentialWrite,
GDAL.OLCRandomWrite,
GDAL.OLCFastSpatialFilter,
GDAL.OLCFastFeatureCount,
GDAL.OLCFastGetExtent,
GDAL.OLCCreateField,
GDAL.OLCDeleteField,
GDAL.OLCReorderFields,
GDAL.OLCAlterFieldDefn,
GDAL.OLCTransactions,
GDAL.OLCDeleteFeature,
GDAL.OLCFastSetNextByIndex,
GDAL.OLCStringsAsUTF8,
GDAL.OLCIgnoreFields,
GDAL.OLCCreateGeomField,
GDAL.OLCCurveGeometries,
GDAL.OLCMeasuredGeometries,
),
)::Dict{String,Bool}
return Dict{String,Bool}([
c => testcapability(layer, c) for c in capabilities
],)
end
# TODO use syntax below once v0.4 support is dropped (not in Compat.jl)
# listcapability(layer::AbstractFeatureLayer) = Dict(
# c => testcapability(layer,c) for c in
# (GDAL.OLCRandomRead, GDAL.OLCSequentialWrite, GDAL.OLCRandomWrite,
# GDAL.OLCFastSpatialFilter, GDAL.OLCFastFeatureCount,GDAL.OLCFastGetExtent,
# GDAL.OLCCreateField, GDAL.OLCDeleteField, GDAL.OLCReorderFields,
# GDAL.OLCAlterFieldDefn, GDAL.OLCTransactions, GDAL.OLCDeleteFeature,
# GDAL.OLCFastSetNextByIndex,GDAL.OLCStringsAsUTF8, GDAL.OLCIgnoreFields,
# GDAL.OLCCreateGeomField, GDAL.OLCCurveGeometries,
# GDAL.OLCMeasuredGeometries)
# )
"""
addfielddefn!(layer::AbstractFeatureLayer, field::AbstractFieldDefn,
approx = false)
Create a new field on a layer.
### Parameters
* `layer`: the layer to write the field definition.
* `field`: the field definition to write to disk.
* `approx`: If `true`, the field may be created in a slightly different form
depending on the limitations of the format driver.
### Remarks
You must use this to create new fields on a real layer. Internally the
OGRFeatureDefn for the layer will be updated to reflect the new field.
Applications should never modify the OGRFeatureDefn used by a layer directly.
This function should not be called while there are feature objects in existence
that were obtained or created with the previous layer definition.
Not all drivers support this function. You can query a layer to check if it
supports it with the `GDAL.OLCCreateField` capability. Some drivers may only
support this method while there are still no features in the layer. When it is
supported, the existing features of the backing file/database should be updated
accordingly.
Drivers may or may not support not-null constraints. If they support creating
fields with not-null constraints, this is generally before creating any feature
to the layer.
"""
function addfielddefn!(
layer::L,
field::AbstractFieldDefn,
approx::Bool = false,
)::L where {L<:AbstractFeatureLayer}
result = GDAL.ogr_l_createfield(layer, field, approx)
@ogrerr result "Failed to create new field"
return layer
end
"""
addgeomdefn!(layer::AbstractFeatureLayer, field::AbstractGeomFieldDefn,
approx = false)
Create a new geometry field on a layer.
### Parameters
* `layer`: the layer to write the field definition.
* `field`: the geometry field definition to write to disk.
* `approx`: If `true`, the field may be created in a slightly different form
depending on the limitations of the format driver.
### Remarks
You must use this to create new geometry fields on a real layer. Internally the
OGRFeatureDefn for the layer will be updated to reflect the new field.
Applications should never modify the OGRFeatureDefn used by a layer directly.
This function should not be called while there are feature objects in existence
that were obtained or created with the previous layer definition.
Not all drivers support this function. You can query a layer to check if it
supports it with the `GDAL.OLCCreateGeomField` capability. Some drivers may only
support this method while there are still no features in the layer. When it is
supported, the existing features of the backing file/database should be updated
accordingly.
Drivers may or may not support not-null constraints. If they support creating
fields with not-null constraints, this is generally before creating any feature
to the layer.
"""
function addgeomdefn!(
layer::L,
field::AbstractGeomFieldDefn,
approx::Bool = false,
)::L where {L<:AbstractFeatureLayer}
result = GDAL.ogr_l_creategeomfield(layer, field, approx)
# OGRERR_NONE on success.
@ogrerr result "Failed to create new geometry field"
return layer
end
# """
# Delete the field at index `i` on a layer.
# You must use this to delete existing fields on a real layer. Internally the
# OGRFeatureDefn for the layer will be updated to reflect the deleted field.
# Applications should never modify the OGRFeatureDefn used by a layer directly.
# This function should not be called while there are feature objects in existence
# that were obtained or created with the previous layer definition.
# Not all drivers support this function. You can query a layer to check if it
# supports it with the OLCDeleteField capability. Some drivers may only support
# this method while there are still no features in the layer. When it is
# supported, the existing features of the backing file/database should be updated
# accordingly.
# ### Parameters
# * `layer`: handle to the layer.
# * `i`: index of the field to delete.
# """
# function deletefield!(layer::AbstractFeatureLayer, i::Integer)
# result = GDAL.ogr_l_deletefield(layer, i)
# @ogrerr result "Failed to delete field $i"
# layer
# end
# # function deletegeomdefn!(layer::AbstractFeatureLayer, i::Integer)
# # error("OGR_L_DeleteGeomField() is not implemented in GDAL yet.")
# # end
# """
# Reorder all the fields of a layer.
# You must use this to reorder existing fields on a real layer. Internally the
# OGRFeatureDefn for the layer will be updated to reflect the reordering of the
# fields. Applications should never modify the OGRFeatureDefn used by a layer
# directly.
# This method should not be called while there are feature objects in existence
# that were obtained or created with the previous layer definition.
# panMap is such that,for each field definition at position i after reordering,
# its position before reordering was panMap[i].
# For example, let suppose the fields were "0","1","2","3","4" initially.
# ReorderFields([0,2,3,1,4]) will reorder them as "0","2","3","1","4".
# Not all drivers support this method. You can query a layer to check if it
# supports it with the OLCReorderFields capability. Some drivers may only support
# this method while there are still no features in the layer. When it is
# supported, the existing features of the backing file/database should be updated
# accordingly.
# ### Parameters
# * `layer`: handle to the layer.
# * `indices`: an array of GetLayerDefn()->OGRFeatureDefn::GetFieldCount()
# elements which is a permutation of
# `[0, GetLayerDefn()->OGRFeatureDefn::GetFieldCount()-1]`.
# """
# function reorderfields!(layer::AbstractFeatureLayer, indices::Vector{Cint})
# result = GDAL.ogr_l_reorderfields(layer, indices)
# @ogrerr result "Failed to reorder the fields of layer according to $indices"
# layer
# end
# """
# Reorder an existing field on a layer.
# This method is a convenience wrapper of ReorderFields() dedicated to move a
# single field. It is a non-virtual method, so drivers should implement
# ReorderFields() instead.
# You must use this to reorder existing fields on a real layer. Internally the
# OGRFeatureDefn for the layer will be updated to reflect the reordering of the
# fields. Applications should never modify the OGRFeatureDefn used by a layer
# directly.
# This method should not be called while there are feature objects in existence
# that were obtained or created with the previous layer definition.
# The field definition that was at initial position iOldFieldPos will be moved at
# position iNewFieldPos, and elements between will be shuffled accordingly.
# For example, let suppose the fields were "0","1","2","3","4" initially.
# ReorderField(1, 3) will reorder them as "0","2","3","1","4".
# Not all drivers support this method. You can query a layer to check if it
# supports it with the OLCReorderFields capability. Some drivers may only support
# this method while there are still no features in the layer. When it is
# supported, the existing features of the backing file/database should be updated
# accordingly.
# ### Parameters
# * `layer`: handle to the layer.
# * `oldpos`: previous position of the field to move. Must be in the range
# [0,GetFieldCount()-1].
# * `newpos`: new position of the field to move. Must be in the range
# [0,GetFieldCount()-1].
# """
# function reorderfield!(
# layer::AbstractFeatureLayer,
# oldpos::Integer,
# newpos::Integer
# )
# result = GDAL.ogr_l_reorderfield(layer, oldpos, newpos)
# @ogrerr result "Failed to reorder field from $oldpos to $newpos."
# layer
# end
# """
# Alter the definition of an existing field on a layer.
# You must use this to alter the definition of an existing field of a real layer.
# Internally the OGRFeatureDefn for the layer will be updated to reflect the
# altered field. Applications should never modify the OGRFeatureDefn used by a
# layer directly.
# This method should not be called while there are feature objects in existence
# that were obtained or created with the previous layer definition.
# Not all drivers support this method. You can query a layer to check if it
# supports it with the OLCAlterFieldDefn capability. Some drivers may only
# support this method while there are still no features in the layer. When it is
# supported, the existing features of the backing file/database should be updated
# accordingly. Some drivers might also not support all update flags.
# ### Parameters
# * `layer`: handle to the layer.
# * `i`: index of the field whose definition must be altered.
# * `newfielddefn`: new field definition
# * `flags`: combination of ALTER_NAME_FLAG, ALTER_TYPE_FLAG,
# ALTER_WIDTH_PRECISION_FLAG, ALTER_NULLABLE_FLAG and
# ALTER_DEFAULT_FLAG to indicate which of the name and/or type and/or
# width and precision fields and/or nullability from the new field
# definition must be taken into account.
# """
# function alterfielddefn!(
# layer::AbstractFeatureLayer,
# i::Integer,
# newfielddefn::FieldDefn,
# flags::UInt8
# )
# result = OGR.alterfielddefn(layer, i, newfielddefn, flags)
# @ogrerr result "Failed to alter fielddefn of field $i."
# layer
# end