Skip to contents

GDALVector provides an interface for accessing a vector layer in a GDAL dataset and calling methods on the underlying OGRLayer object. An object of class GDALVector persists an open connection to the dataset, and exposes methods for retrieving layer information, setting attribute and spatial filters, and reading/writing feature data. See https://gdal.org/api/index.html for details of the GDAL Vector API.

Class GDALVector is currently under development. An initial implementation supporting read access was added in gdalraster 1.11.1.9100. A working document with draft specifications is available at:
https://usdaforestservice.github.io/gdalraster/articles/gdalvector-draft.html
and discussion thread/status updates at:
https://github.com/USDAForestService/gdalraster/issues/241.

Arguments

dsn

Character string containing the data source name (DSN), usually a filename or database connection string.

layer

Character string containing the name of a layer within the data source. May also be given as an SQL SELECT statement to be executed against the data source, defining a layer as the result set.

read_only

Logical scalar. TRUE to open the layer read-only (the default), or FALSE to open with write access.

open_options

Optional character vector of NAME=VALUE pairs specifying dataset open options.

spatial_filter

Optional character string containing a geometry in Well Known Text (WKT) format which represents a spatial filter.

dialect

Optional character string to control the statement dialect when SQL is used to define the layer. By default, the OGR SQL engine will be used, except for RDBMS drivers that will use their dedicated SQL engine, unless "OGRSQL" is explicitly passed as the dialect. The "SQLITE" dialect can also be used.

Value

An object of class GDALVector which contains pointers to the opened layer and the dataset that owns it, and methods that operate on the layer as described in Details. GDALVector is a C++ class exposed directly to R (via RCPP_EXPOSED_CLASS). Fields and methods of the class are accessed using the $ operator. Note that all arguments to exposed class methods are required (but do not have to be named). The read/write fields are per-object settings which can be changed as needed during the lifetime of the object.

Usage (see Details)


## Constructors
# for single-layer file formats such as shapefile
lyr <- new(GDALVector, dsn)
# specifying the layer name, or SQL statement defining the layer
lyr <- new(GDALVector, dsn, layer)
# for update access
lyr <- new(GDALVector, dsn, layer, read_only = FALSE)
# using dataset open options
lyr <- new(GDALVector, dsn, layer, read_only, open_options)
# setting a spatial filter and/or specifying the SQL dialect
lyr <- new(GDALVector, dsn, layer, read_only, open_options, spatial_filter, dialect)

## Read-only fields
lyr$featureTemplate

## Read/write fields
lyr$defaultGeomFldName
lyr$returnGeomAs
lyr$wkbByteOrder

## Methods
lyr$open(read_only)
lyr$isOpen()
lyr$getDsn()
lyr$getFileList()
lyr$getDriverShortName()
lyr$getDriverLongName()

lyr$getName()
lyr$testCapability()
lyr$getFIDColumn()
lyr$getGeomType()
lyr$getGeometryColumn()
lyr$getSpatialRef()
lyr$bbox()
lyr$getLayerDefn()

lyr$setAttributeFilter(query)
lyr$getAttributeFilter()
lyr$setIgnoredFields(fields)

lyr$setSpatialFilter(wkt)
lyr$setSpatialFilterRect(bbox)
lyr$getSpatialFilter()
lyr$clearSpatialFilter()

lyr$getFeatureCount()
lyr$getNextFeature()
lyr$setNextByIndex(i)
lyr$getFeature(fid)
lyr$resetReading()
lyr$fetch(n)

lyr$deleteFeature(fid)

lyr$startTransaction(force)
lyr$commitTransaction()
lyr$rollbackTransaction()

lyr$close()

Details

Constructors

new(GDALVector, dsn)
The first layer by index is assumed if the layer argument is omitted, so this form of the constructor might be used for single-layer formats like shapefile.

new(GDALVector, dsn, layer)
Constructor specifying the name of a layer to open. The layer argument may also be given as an SQL SELECT statement to define a layer as the result set.

new(GDALVector, dsn, layer, read_only)
Constructor specifying read/write access (read_only = {TRUE|FALSE}). The layer argument is required in this form of the constructor, but may be given as empty string (""), in which case the first layer by index will be assumed.

new(GDALVector, dsn, layer, read_only, open_options)
Constructor specifying dataset open options as a character vector of NAME=VALUE pairs.

new(GDALVector, dsn, layer, read_only, open_options, spatial_filter, dialect))
Constructor to specify a spatial filter and/or SQL dialect. All arguments are required in this form of the constructor, but open_options may be NULL, and spatial_filter or dialect may be an empty string ("").

Read-only fields

$featureTemplate
A list of the attribute and geometry field names, with NA values equivalent to OGR NULL values. The list elements are fully typed with the corresponding missing value types assigned (NA_integer_, NA_real_, NA_character_, etc.). The featureTemplate is useful to initialize a new empty feature, to which field and geometry values can be assigned, for use with the $createFeature() method (create and write a new feature within the layer). Note that geometry fields are initialized as character type in the template, but may be set either to a character string specifying a geometry in WKT format, or to a raw vector containing a geometry as WKB.

Read/write fields

$defaultGeomFldName
Character string specifying a name to use for returned columns when the geometry column name in the source layer is empty, like with shapefiles etc. Defaults to "geometry".

$returnGeomAs
Character string specifying the return format of feature geometries. Must be one of WKT, WKT_ISO, WKB, WKB_ISO, TYPE_NAME or NONE (the default). Using WKB/WKT exports as 99-402 extended dimension (Z) types for Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon and GeometryCollection. For other geometry types, it is equivalent to using WKB_ISO/WKT_ISO (see https://libgeos.org/specifications/wkb/).

$wkbByteOrder
Character string specifying the byte order for WKB geometries. Must be either LSB (Least Significant Byte first, the default) or MSB (Most Significant Byte first).

Methods

$open(read_only)
(Re-)opens the vector layer on the existing DSN. Use this method to open a layer that has been closed using $close(). May be used to re-open a layer with a different read/write access (read_only set to TRUE or FALSE). The method will first close an open dataset, so it is not required to call $close() explicitly in this case. No return value, called for side effects.

$isOpen()
Returns a logical scalar indicating whether the vector dataset is open.

$getDsn()
Returns a character string containing the dsn associated with this GDALVector object (dsn originally used to open the layer).

$getFileList()
Returns a character vector of files believed to be part of the data source. If it returns an empty string ("") it means there is believed to be no local file system files associated with the dataset (e.g., a virtual file system). The returned filenames will normally be relative or absolute paths depending on the path used to originally open the dataset.

$getDriverShortName()
Returns the short name of the vector format driver.

$getDriverLongName()
Returns the long name of the vector format driver.

$getName()
Returns the layer name.

$testCapability()
Tests whether the layer supports named capabilities based on the current read/write access. Returns a list of capabilities with values TRUE or FALSE. The returned list contains the following named elements: RandomRead, SequentialWrite, RandomWrite, UpsertFeature, FastSpatialFilter, FastFeatureCount, FastGetExtent, FastSetNextByIndex, CreateField, CreateGeomField, DeleteField, ReorderFields, AlterFieldDefn, AlterGeomFieldDefn, DeleteFeature, StringsAsUTF8, Transactions, CurveGeometries. (See the GDAL documentation for OGR_L_TestCapability().)

$getFIDColumn()
Returns the name of the underlying database column being used as the FID column, or empty string ("") if not supported.

$getGeomType()
Returns the well known name of the layer geometry type as character string. For layers with multiple geometry fields, this method only returns the geometry type of the first geometry column. For other columns, use $getLayerDefn(). For layers without any geometry field, this method returns "NONE".

$getGeometryColumn()
Returns he name of the underlying database column being used as the geometry column, or an empty string ("") if not supported. For layers with multiple geometry fields, this method only returns the name of the first geometry column. For other columns, use $getLayerDefn().

$getSpatialRef()
Returns a WKT string containing the spatial reference system for this layer, or empty string ("") if no spatial reference exists.

$bbox()
Returns a numeric vector of length four containing the bounding box for this layer (xmin, ymin, xmax, ymax). Note that bForce = true is set in the underlying API call to OGR_L_GetExtent(), so the entire layer may be scanned to compute a minimum bounding rectangle (see FastGetExtent in the list returned by $testCapability()). Depending on the format driver, a spatial filter may or may not be taken into account, so it is safer to call $bbox() without setting a spatial filter.

$getLayerDefn()
Returns a list containing the OGR feature class definition for this layer (a.k.a. layer definition). The list contains zero or more attribute field definitions, along with one or more geometry field definitions. See ogr_define for details of the field and feature class definitions.

$setAttributeFilter(query)
Sets an attribute query string to be used when fetching features via the $getNextFeature() or $fetch() methods. Only features for which query evaluates as true will be returned. The query string should be in the format of an SQL WHERE clause, described in the "WHERE" section of the OGR SQL dialect documentation (e.g., "population > 1000000 and population < 5000000", where population is an attribute in the layer). In some cases (RDBMS backed drivers, SQLite, GeoPackage) the native capabilities of the database may be used to 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 (as with $resetReading() described below). The query parameter may be set to empty string ("") to clear the current attribute filter.

$getAttributeFilter()
Returns the attribute query string currently in use, or empty string ("") if an attribute filter is not set.

$setIgnoredFields(fields)
Set which fields can be omitted when retrieving features from the layer. The fields argument is a character vector of field names. If the format driver supports this functionality (testable using $testCapability()$IgnoreFields), it will not fetch the specified fields in subsequent calls to $getFeature() / $getNextFeature() / $fetch(), and thus save some processing time and/or bandwidth. Besides field names of the layer, the following special fields can be passed: "OGR_GEOMETRY" to ignore geometry and "OGR_STYLE" to ignore layer style. By default, no fields are ignored. Note that fields that are used in an attribute filter should generally not be set as ignored fields, as most drivers (such as those relying on the OGR SQL engine) will be unable to correctly evaluate the attribute filter. No return value, called for side effects.

$setSpatialFilter(wkt)
Sets a new spatial filter from a geometry in WKT format. This method sets the geometry to be used as a spatial filter when fetching features via the $getNextFeature() or $fetch() methods. Only features that geometrically intersect the filter geometry will be returned. Currently this test may be inaccurately implemented (depending on the vector format driver), but it is guaranteed that all features whose envelope overlaps the envelope of the spatial filter will be returned. This can result in more shapes being returned that should strictly be the case. wkt is a character string containing a WKT geometry in the same coordinate system as the layer. An empty string ("") may be passed indicating that the current spatial filter should be cleared, but no new one instituted.

$setSpatialFilterRect(bbox)
Sets a new rectangular spatial filter. This method sets a rectangle to be used as a spatial filter when fetching features via the $getNextFeature() or $fetch() methods. Only features that geometrically intersect the given rectangle will be returned. bbox is a numeric vector of length four containing xmin, ymin, xmax, ymax in the same coordinate system as the layer as a whole (as returned by $getSpatialRef()).

$getSpatialFilter()
Returns the current spatial filter geometry as a WKT string, or empty string ("") if a spatial filter is not set.

$clearSpatialFilter()
Clears a spatial filter that was set with $setSpatialFilterRect(). No return value, called for that side effect.

$getFeatureCount()
Returns the number of features in the layer. For dynamic databases the count may not be exact. This method forces a count in the underlying API call (i.e., bForce = TRUE in the call to OGR_L_GetFeatureCount()). Note that some vector drivers will actually scan the entire layer once to count features. The FastFeatureCount element in the list returned by the $testCapability() method can be checked if this might be a concern. The number of features returned takes into account the spatial and/or attribute filters. Some driver implementations of this method may alter the read cursor of the layer.

$getNextFeature()
Fetch the next available feature from this layer. Only features matching the current spatial and/or attribute filter (if defined) will be returned. This method implements sequential access to the features of a layer. The $resetReading() method can be used to start at the beginning again. Returns a list with the unique feature identifier (FID), the attribute and geometry field names, and their values. NULL is returned if no more features are available.

$setNextByIndex(i)
Moves the read cursor to the ith feature in the current result set (with 0-based indexing). This method allows positioning of a layer such that a call to $getNextFeature() or fetch() will read the requested feature(s), where i is an absolute index into the current result set. So, setting i = 3 would mean the next feature read with $getNextFeature() would have been the 4th feature read if sequential reading took place from the beginning of the layer, including accounting for spatial and attribute filters. This method is not implemented efficiently by all vector format drivers. The default implementation simply resets reading to the beginning and then calls GetNextFeature() i times. To determine if fast seeking is available on the current layer, check the FastSetNextByIndex element in the list returned by the $testCapability() method. No return value, called for side effect.

$getFeature(fid)
Returns a feature by its identifier. The value of fid must be a numeric scalar, optionally carrying the bit64::integer64 class attribute. Success or failure of this operation is unaffected by any spatial or attribute filters that may be in effect. The RandomRead element in the list returned by $testCapability() can be checked to establish if this layer supports efficient random access reading; however, the call should always work if the feature exists since a fallback implementation just scans all the features in the layer looking for the desired feature. Returns a list with the unique feature identifier (FID), the attribute and geometry field names, and their values, or NULL on failure. Note that sequential reads (with $getNextFeature()) are generally considered interrupted by a call to $getFeature().

$resetReading()
Reset feature reading to start on the first feature. No return value, called for that side effect.

$fetch(n)
Fetches the next n features from the layer and returns them as a data frame. This allows retrieving the entire set of features, one page of features at a time, or the remaining features (from the current cursor position). Returns a data frame with as many rows as features were fetched, and as many columns as attribute plus geometry fields in the result set, even if the result is a single value or has one or zero rows.

This method is an analog of DBI::dbFetch().

The n argument is the maximum number of features to retrieve per fetch given as integer or numeric but assumed to be a whole number (will be truncated). Use n = -1 or n = Inf to retrieve all pending features (resets reading to the first feature). Otherwise, $fetch() can be called multiple times to perform forward paging from the current cursor position. Passing n = NA is also supported and returns the remaining features. Fetching zero features is possible to retrieve the structure of the feature set as a data frame (columns fully typed).

OGR field types are returned as the following R types (NA for OGR NULL values):

  • OFTInteger: integer

  • OFTInteger subtype OFSTBoolean: logical

  • OFTIntegerList: vector of integer (list column)

  • OFTInteger64: bit64::integer64

  • OFTInteger64 subtype OFSTBoolean: logical

  • OFTInteger64List: vector of bit64::integer64 (list column)

  • OFTReal: numeric

  • OFTRealList: vector of numeric (list column)

  • OFTString: character string

  • OFTStringList: vector of character strings (list column)

  • OFTDate: Date

  • OFTDateTime: POSIXct (millisecond accuracy and adjustment for time zone flag if present)

  • OFTBinary: raw vector (list column, NULL entries for OGR NULL values)

Geomtries are not returned if the field returnGeomAs is set to NONE (currently the default). Omitting the geometries may be beneficial for performance and memory usage when access only to feature attributes is needed. Geometries are returned as raw vectors in a data frame list column when returnGeomAs is set to WKB or WKB_ISO. Otherwise, geometries are returned as character strings when returnGeomAs is set to one of WKT, WKT_ISO or TYPE_NAME.

Note that $getFeatureCount() is called internally when fetching the full feature set or all remaining features (but not for a page of features).

$deleteFeature(fid)
Deletes a feature from the layer. The feature with the indicated feature ID is deleted from the layer if supported by the format driver. The value of fid must be a numeric scalar, optionally carrying the bit64::integer64 class attribute (should be a whole number, will be truncated). The DeleteFeature element in the list returned by $testCapability() can be checked to establish if this layer has delete feature capability. Returns logical TRUE if the operation succeeds, or FALSE on failure.

$startTransaction(force)
Creates a transaction if supported by the vector data source. The force argument is a logical value. If force = FALSE, only "efficient" transactions will be attempted. Some drivers may offer an emulation of transactions, but sometimes with significant overhead, in which case the user must explicitly allow for such an emulation by setting force =TRUE. The function ogr_ds_test_cap() can be used to determine whether a vector data source supports efficient or emulated transactions.

All changes done after the start of the transaction are definitely applied in the data source if $commitTransaction() is called. They can be canceled by calling rollbackTransaction() instead. Nested transactions are not supported. Transactions are implemented at the dataset level, so multiple GDALVector objects using the same data source should not have transactions active at the same time.

In case $startTransaction() fails, neither $commitTransaction() nor $rollbackTransaction() should be called. If an error occurs after a successful $startTransaction(), the whole transaction may or may not be implicitly canceled, depending on the format driver (e.g., the PostGIS driver will cancel it, SQLite/GPKG will not). In any case, in the event of an error, an explicit call to rollbackTransaction() should be done to keep things balanced.

Returns logical TRUE if the transaction is created, or FALSE on failure.

$commitTransaction()
Commits a transaction if supported by the vector data source. Returns a logical value, TRUE if the transaction is successfully committed. Returns FALSE if no transaction is active, or the rollback fails, or if the data source does not support transactions. Depending on the format driver, this may or may not abort layer sequential reading that may be active.

$rollbackTransaction()
Rolls back a data source to its state before the start of the current transaction, if transactions are supported by the data source. Returns a logical value, TRUE if the transaction is successfully rolled back. Returns FALSE if no transaction is active, or the rollback fails, or if the data source does not support transactions.

$close()
Closes the vector dataset (no return value, called for side effects). Calling $close() results in proper cleanup, and flushing of any pending writes. The GDALVector object is still available after calling $close(). The layer can be re-opened on the existing dsn with $open(read_only = {TRUE|FALSE}).

Examples

# MTBS fire perimeters in Yellowstone National Park 1984-2022
f <- system.file("extdata/ynp_fires_1984_2022.gpkg", package = "gdalraster")

# copy to a temporary file that is writeable
dsn <- file.path(tempdir(), basename(f))
file.copy(f, dsn)
#> [1] TRUE

lyr <- new(GDALVector, dsn, "mtbs_perims")

# object of class GDALVector
lyr
#> C++ object <0x562638f7bfd0> of class 'GDALVector' <0x56262e97ba30>
str(lyr)
#> Reference class 'Rcpp_GDALVector' [package "gdalraster"] with 7 fields
#>  $ defaultGeomFldName: chr "geometry"
#>  $ featureTemplate   :List of 11
#>   ..$ FID         :integer64 NA 
#>   ..$ event_id    : chr NA
#>   ..$ incid_name  : chr NA
#>   ..$ incid_type  : chr NA
#>   ..$ map_id      :integer64 NA 
#>   ..$ burn_bnd_ac :integer64 NA 
#>   ..$ burn_bnd_lat: chr NA
#>   ..$ burn_bnd_lon: chr NA
#>   ..$ ig_date     : Date[1:1], format: NA
#>   ..$ ig_year     : int NA
#>   ..$ geom        : chr NA
#>  $ m_dialect         : chr ""
#>  $ m_is_sql          : logi FALSE
#>  $ m_layer_name      : chr "mtbs_perims"
#>  $ returnGeomAs      : chr "NONE"
#>  $ wkbByteOrder      : chr "LSB"
#>  and 55 methods, of which 41 are  possibly relevant:
#>    bbox, clearSpatialFilter, close, commitTransaction, deleteFeature, fetch,
#>    finalize, getAttributeFilter, getDriverLongName, getDriverShortName, getDsn,
#>    getFIDColumn, getFeature, getFeatureCount, getFileList, getGeomType,
#>    getGeometryColumn, getLayerDefn, getName, getNextFeature, getSpatialFilter,
#>    getSpatialRef, initialize, isOpen, layerClip, layerErase, layerIdentity,
#>    layerIntersection, layerSymDifference, layerUnion, layerUpdate, open,
#>    resetReading, rollbackTransaction, setAttributeFilter, setIgnoredFields,
#>    setNextByIndex, setSpatialFilter, setSpatialFilterRect, startTransaction,
#>    testCapability

# dataset info
lyr$getDriverShortName()
#> [1] "GPKG"
lyr$getDriverLongName()
#> [1] "GeoPackage"
lyr$getFileList()
#> [1] "/tmp/Rtmpguep89/ynp_fires_1984_2022.gpkg"

# layer info
lyr$getName()
#> [1] "mtbs_perims"
lyr$getGeomType()
#> [1] "MULTIPOLYGON"
lyr$getGeometryColumn()
#> [1] "geom"
lyr$getFIDColumn()
#> [1] "fid"
lyr$getSpatialRef()
#> [1] "PROJCS[\"NAD83 / Montana\",GEOGCS[\"NAD83\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS 1980\",6378137,298.257222101,AUTHORITY[\"EPSG\",\"7019\"]],AUTHORITY[\"EPSG\",\"6269\"]],PRIMEM[\"Greenwich\",0,AUTHORITY[\"EPSG\",\"8901\"]],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]],AUTHORITY[\"EPSG\",\"4269\"]],PROJECTION[\"Lambert_Conformal_Conic_2SP\"],PARAMETER[\"latitude_of_origin\",44.25],PARAMETER[\"central_meridian\",-109.5],PARAMETER[\"standard_parallel_1\",49],PARAMETER[\"standard_parallel_2\",45],PARAMETER[\"false_easting\",600000],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH],AUTHORITY[\"EPSG\",\"32100\"]]"
lyr$bbox()
#> [1] 469685.73 -12917.76 573531.72  96577.34

# layer capabilities
lyr$testCapability()
#> $RandomRead
#> [1] TRUE
#> 
#> $SequentialWrite
#> [1] FALSE
#> 
#> $RandomWrite
#> [1] FALSE
#> 
#> $FastSpatialFilter
#> [1] TRUE
#> 
#> $FastFeatureCount
#> [1] TRUE
#> 
#> $FastGetExtent
#> [1] TRUE
#> 
#> $FastSetNextByIndex
#> [1] FALSE
#> 
#> $CreateField
#> [1] FALSE
#> 
#> $CreateGeomField
#> [1] FALSE
#> 
#> $DeleteField
#> [1] FALSE
#> 
#> $ReorderFields
#> [1] FALSE
#> 
#> $AlterFieldDefn
#> [1] FALSE
#> 
#> $IgnoreFields
#> [1] TRUE
#> 
#> $DeleteFeature
#> [1] FALSE
#> 
#> $StringsAsUTF8
#> [1] TRUE
#> 
#> $CurveGeometries
#> [1] TRUE
#> 

# re-open with write access
lyr$open(read_only = FALSE)
lyr$testCapability()$SequentialWrite
#> [1] TRUE
lyr$testCapability()$RandomWrite
#> [1] TRUE

# feature class definition - a list of field names and their definitions
defn <- lyr$getLayerDefn()
names(defn)
#>  [1] "event_id"     "incid_name"   "incid_type"   "map_id"       "burn_bnd_ac" 
#>  [6] "burn_bnd_lat" "burn_bnd_lon" "ig_date"      "ig_year"      "geom"        
str(defn)
#> List of 10
#>  $ event_id    :List of 9
#>   ..$ type       : chr "OFTString"
#>   ..$ subtype    : chr "OFSTNone"
#>   ..$ width      : int 254
#>   ..$ precision  : int 0
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_unique  : logi FALSE
#>   ..$ default    : chr ""
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi FALSE
#>  $ incid_name  :List of 9
#>   ..$ type       : chr "OFTString"
#>   ..$ subtype    : chr "OFSTNone"
#>   ..$ width      : int 254
#>   ..$ precision  : int 0
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_unique  : logi FALSE
#>   ..$ default    : chr ""
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi FALSE
#>  $ incid_type  :List of 9
#>   ..$ type       : chr "OFTString"
#>   ..$ subtype    : chr "OFSTNone"
#>   ..$ width      : int 254
#>   ..$ precision  : int 0
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_unique  : logi FALSE
#>   ..$ default    : chr ""
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi FALSE
#>  $ map_id      :List of 9
#>   ..$ type       : chr "OFTInteger64"
#>   ..$ subtype    : chr "OFSTNone"
#>   ..$ width      : int 0
#>   ..$ precision  : int 0
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_unique  : logi FALSE
#>   ..$ default    : chr ""
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi FALSE
#>  $ burn_bnd_ac :List of 9
#>   ..$ type       : chr "OFTInteger64"
#>   ..$ subtype    : chr "OFSTNone"
#>   ..$ width      : int 0
#>   ..$ precision  : int 0
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_unique  : logi FALSE
#>   ..$ default    : chr ""
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi FALSE
#>  $ burn_bnd_lat:List of 9
#>   ..$ type       : chr "OFTString"
#>   ..$ subtype    : chr "OFSTNone"
#>   ..$ width      : int 10
#>   ..$ precision  : int 0
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_unique  : logi FALSE
#>   ..$ default    : chr ""
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi FALSE
#>  $ burn_bnd_lon:List of 9
#>   ..$ type       : chr "OFTString"
#>   ..$ subtype    : chr "OFSTNone"
#>   ..$ width      : int 10
#>   ..$ precision  : int 0
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_unique  : logi FALSE
#>   ..$ default    : chr ""
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi FALSE
#>  $ ig_date     :List of 9
#>   ..$ type       : chr "OFTDate"
#>   ..$ subtype    : chr "OFSTNone"
#>   ..$ width      : int 0
#>   ..$ precision  : int 0
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_unique  : logi FALSE
#>   ..$ default    : chr ""
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi FALSE
#>  $ ig_year     :List of 9
#>   ..$ type       : chr "OFTInteger"
#>   ..$ subtype    : chr "OFSTNone"
#>   ..$ width      : int 0
#>   ..$ precision  : int 0
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_unique  : logi FALSE
#>   ..$ default    : chr ""
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi FALSE
#>  $ geom        :List of 5
#>   ..$ type       : chr "MULTIPOLYGON"
#>   ..$ srs        : chr "PROJCS[\"NAD83 / Montana\",GEOGCS[\"NAD83\",DATUM[\"North_American_Datum_1983\",SPHEROID[\"GRS 1980\",6378137,2"| __truncated__
#>   ..$ is_nullable: logi TRUE
#>   ..$ is_ignored : logi FALSE
#>   ..$ is_geom    : logi TRUE

# default value of the read/write field 'returnGeomAs'
print(lyr$returnGeomAs)
#> [1] "NONE"

lyr$getFeatureCount()
#> [1] 61

# sequential read cursor
feat <- lyr$getNextFeature()
# a list of field names and their values
str(feat)
#> List of 10
#>  $ FID         :integer64 1 
#>  $ event_id    : chr "WY4413411069519870807"
#>  $ incid_name  : chr "POLECAT"
#>  $ incid_type  : chr "Wildfire"
#>  $ map_id      :integer64 10015934 
#>  $ burn_bnd_ac :integer64 1093 
#>  $ burn_bnd_lat: chr "44.132"
#>  $ burn_bnd_lon: chr "-110.696"
#>  $ ig_date     : Date[1:1], format: "1987-08-07"
#>  $ ig_year     : int 1987

# set an attribute filter
lyr$setAttributeFilter("ig_year = 2020")
lyr$getFeatureCount()
#> [1] 1

feat <- lyr$getNextFeature()
str(feat)
#> List of 10
#>  $ FID         :integer64 61 
#>  $ event_id    : chr "WY4438911082120200822"
#>  $ incid_name  : chr "LONE STAR"
#>  $ incid_type  : chr "Wildfire"
#>  $ map_id      :integer64 10020495 
#>  $ burn_bnd_ac :integer64 3348 
#>  $ burn_bnd_lat: chr "44.4"
#>  $ burn_bnd_lon: chr "-110.782"
#>  $ ig_date     : Date[1:1], format: "2020-08-22"
#>  $ ig_year     : int 2020

# NULL when no more features are available
feat <- lyr$getNextFeature()
str(feat)
#>  NULL

# reset reading to the start and return geometries as WKT
lyr$resetReading()
lyr$returnGeomAs <- "WKT"
feat <- lyr$getNextFeature()
str(feat)
#> List of 11
#>  $ FID         :integer64 61 
#>  $ event_id    : chr "WY4438911082120200822"
#>  $ incid_name  : chr "LONE STAR"
#>  $ incid_type  : chr "Wildfire"
#>  $ map_id      :integer64 10020495 
#>  $ burn_bnd_ac :integer64 3348 
#>  $ burn_bnd_lat: chr "44.4"
#>  $ burn_bnd_lon: chr "-110.782"
#>  $ ig_date     : Date[1:1], format: "2020-08-22"
#>  $ ig_year     : int 2020
#>  $ geom        : chr "MULTIPOLYGON (((496593.122306971 15506.8828590633,496491.761299067 15605.3612548792,496290.812130161 15388.0465"| __truncated__

# clear the attribute filter
lyr$setAttributeFilter("")
lyr$getFeatureCount()
#> [1] 61

# set a spatial filter
# get the bounding box of the largest 1988 fire and use as spatial filter
# first set a temporary attribute filter to do the lookup
lyr$setAttributeFilter("ig_year = 1988 ORDER BY burn_bnd_ac DESC")
feat <- lyr$getNextFeature()
str(feat)
#> List of 11
#>  $ FID         :integer64 7 
#>  $ event_id    : chr "WY4470811082119880722"
#>  $ incid_name  : chr "NORTH FORK"
#>  $ incid_type  : chr "Wildfire"
#>  $ map_id      :integer64 10014217 
#>  $ burn_bnd_ac :integer64 563527 
#>  $ burn_bnd_lat: chr "44.678"
#>  $ burn_bnd_lon: chr "-110.716"
#>  $ ig_date     : Date[1:1], format: "1988-07-22"
#>  $ ig_year     : int 1988
#>  $ geom        : chr "MULTIPOLYGON (((469685.969312071 29526.2354109807,469918.933844832 29654.3220754602,470030.299119989 29518.7441"| __truncated__

bbox <- bbox_from_wkt(feat$geom)
print(bbox)
#> [1] 469685.97  11442.45 544069.63  85508.15

# set spatial filter on the full layer
lyr$setAttributeFilter("")
lyr$setSpatialFilterRect(bbox)
lyr$getFeatureCount()
#> [1] 40

# fetch in chunks and return as data frame
d <- lyr$fetch(20)
str(d)
#> 'data.frame':	20 obs. of  11 variables:
#>  $ FID         :integer64 38 7 32 25 6 40 36 8 ... 
#>  $ event_id    : chr  "MT4471311115120070627" "WY4470811082119880722" "MT4491211108020030820" "WY4433011103020000816" ...
#>  $ incid_name  : chr  "MADISON ARM" "NORTH FORK" "RATHBONE" "SPRUCE COMPLEX (PLATEAU)" ...
#>  $ incid_type  : chr  "Wildfire" "Wildfire" "Wildfire" "Wildfire" ...
#>  $ map_id      :integer64 16113 10014217 13014 10014141 10014215 16428 15432 10014218 ... 
#>  $ burn_bnd_ac :integer64 3564 563527 2701 2808 20422 2175 3745 95233 ... 
#>  $ burn_bnd_lat: chr  "44.713" "44.678" "44.912" "44.329" ...
#>  $ burn_bnd_lon: chr  "-111.151" "-110.716" "-111.080" "-111.027" ...
#>  $ ig_date     : Date, format: "2007-06-27" "1988-07-22" ...
#>  $ ig_year     : int  2007 1988 2003 2000 1988 2007 2006 1988 1988 1988 ...
#>  $ geom        : chr  "MULTIPOLYGON (((469685.969631834 54506.9481370259,470235.509134591 54383.4837249131,470939.42854159 53898.69574"| __truncated__ "MULTIPOLYGON (((469685.969312071 29526.2354109807,469918.933844832 29654.3220754602,470030.299119989 29518.7441"| __truncated__ "MULTIPOLYGON (((475136.766856355 74053.2153491452,475188.847231864 74366.3342955356,475341.959781024 74368.4856"| __truncated__ "MULTIPOLYGON (((477992.723214764 8483.08443989834,477312.456870818 7630.95433906866,477088.305832492 6955.09786"| __truncated__ ...

# the next chunk
d <- lyr$fetch(20)
nrow(d)
#> [1] 20

# no features remaining
d <- lyr$fetch(20)
nrow(d)
#> [1] 0
str(d) # 0-row data frame with columns typed
#> 'data.frame':	0 obs. of  11 variables:
#>  $ FID         :integer64  
#>  $ event_id    : chr 
#>  $ incid_name  : chr 
#>  $ incid_type  : chr 
#>  $ map_id      :integer64  
#>  $ burn_bnd_ac :integer64  
#>  $ burn_bnd_lat: chr 
#>  $ burn_bnd_lon: chr 
#>  $ ig_date     : 'Date' num(0) 
#>  $ ig_year     : int 
#>  $ geom        : chr 

# fetch all pending features with geometries as WKB
lyr$returnGeomAs <- "WKB"
d <- lyr$fetch(-1)  # resets reading to the first feature
str(d)
#> 'data.frame':	40 obs. of  11 variables:
#>  $ FID         :integer64 38 7 32 25 6 40 36 8 ... 
#>  $ event_id    : chr  "MT4471311115120070627" "WY4470811082119880722" "MT4491211108020030820" "WY4433011103020000816" ...
#>  $ incid_name  : chr  "MADISON ARM" "NORTH FORK" "RATHBONE" "SPRUCE COMPLEX (PLATEAU)" ...
#>  $ incid_type  : chr  "Wildfire" "Wildfire" "Wildfire" "Wildfire" ...
#>  $ map_id      :integer64 16113 10014217 13014 10014141 10014215 16428 15432 10014218 ... 
#>  $ burn_bnd_ac :integer64 3564 563527 2701 2808 20422 2175 3745 95233 ... 
#>  $ burn_bnd_lat: chr  "44.713" "44.678" "44.912" "44.329" ...
#>  $ burn_bnd_lon: chr  "-111.151" "-110.716" "-111.080" "-111.027" ...
#>  $ ig_date     : Date, format: "2007-06-27" "1988-07-22" ...
#>  $ ig_year     : int  2007 1988 2003 2000 1988 2007 2006 1988 1988 1988 ...
#>  $ geom        :List of 40
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...
#>   ..$ : raw  01 06 00 00 ...

# parse WKB using package wk
wk_obj <- wk::wkb(d$geom, crs = lyr$getSpatialRef())
plot(wk_obj)


lyr$clearSpatialFilter()
lyr$getFeatureCount()
#> [1] 61

lyr$close()
unlink(dsn)