Skip to content

Commit

Permalink
add get_features_by_fid
Browse files Browse the repository at this point in the history
  • Loading branch information
jorisvandenbossche committed Oct 16, 2021
1 parent fa5688a commit ba804ce
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 17 deletions.
111 changes: 94 additions & 17 deletions pyogrio/_io.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,64 @@ cdef get_features(
return (geometries, field_data)


@cython.boundscheck(False) # Deactivate bounds checking
@cython.wraparound(False) # Deactivate negative indexing.
cdef get_features_by_fid(
OGRLayerH ogr_layer,
int[:] fids,
object[:,:] fields,
encoding,
uint8_t read_geometry,
uint8_t force_2d):

cdef OGRFeatureH ogr_feature = NULL
cdef int n_fields
cdef int i
cdef int fid
cdef int field_index
cdef int count

# make sure layer is read from beginning
OGR_L_ResetReading(ogr_layer)

count = len(fids)

if read_geometry:
geometries = np.empty(shape=(count, ), dtype='object')
geom_view = geometries[:]

else:
geometries = None

n_fields = fields.shape[0]
field_indexes = fields[:,0]
field_ogr_types = fields[:,1]

field_data = [
np.empty(shape=(count, ),
dtype=fields[field_index,3]) for field_index in range(n_fields)
]

field_data_view = [field_data[field_index][:] for field_index in range(n_fields)]

for i in range(count):
fid = fids[i]

ogr_feature = OGR_L_GetFeature(ogr_layer, fid)

if ogr_feature == NULL:
raise ValueError("Failed to read feature {}".format(i))

if read_geometry:
process_geometry(ogr_feature, i, geom_view, force_2d)

process_fields(
ogr_feature, i, n_fields, field_data, field_data_view, field_indexes, field_ogr_types, encoding
)

return (geometries, field_data)


@cython.boundscheck(False) # Deactivate bounds checking
@cython.wraparound(False) # Deactivate negative indexing.
cdef get_bounds(
Expand Down Expand Up @@ -632,6 +690,7 @@ def ogr_read(
int max_features=0,
object where=None,
tuple bbox=None,
object fids=None,
**kwargs):

cdef int err = 0
Expand All @@ -652,16 +711,23 @@ def ogr_read(
ogr_dataset = ogr_open(path_c, 0, kwargs)
ogr_layer = get_ogr_layer(ogr_dataset, layer)

# Apply the attribute filter
if where is not None and where != "":
apply_where_filter(ogr_layer, where)
if fids is not None:
if where is not None or bbox is not None or skip_features or max_features:
raise ValueError(
"cannot set both 'fids' and one of 'where', 'bbox', "
"'skip_features' or 'max_features'")
fids = np.asarray(fids, dtype=np.intc)
else:
# Apply the attribute filter
if where is not None and where != "":
apply_where_filter(ogr_layer, where)

# Apply the spatial filter
if bbox is not None:
apply_spatial_filter(ogr_layer, bbox)
# Apply the spatial filter
if bbox is not None:
apply_spatial_filter(ogr_layer, bbox)

# Limit feature range to available range
skip_features, max_features = validate_feature_range(ogr_layer, skip_features, max_features)
# Limit feature range to available range
skip_features, max_features = validate_feature_range(ogr_layer, skip_features, max_features)

crs = get_crs(ogr_layer)

Expand All @@ -682,15 +748,26 @@ def ogr_read(

geometry_type = get_geometry_type(ogr_layer)

geometries, field_data = get_features(
ogr_layer,
fields,
encoding,
read_geometry=read_geometry and geometry_type is not None,
force_2d=force_2d,
skip_features=skip_features,
max_features=max_features,
)
if fids is not None:
geometries, field_data = get_features_by_fid(
ogr_layer,
fids,
fields,
encoding,
read_geometry=read_geometry and geometry_type is not None,
force_2d=force_2d,
)

else:
geometries, field_data = get_features(
ogr_layer,
fields,
encoding,
read_geometry=read_geometry and geometry_type is not None,
force_2d=force_2d,
skip_features=skip_features,
max_features=max_features,
)

meta = {
'crs': crs,
Expand Down
1 change: 1 addition & 0 deletions pyogrio/_ogr.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ cdef extern from "ogr_api.h":
int OGR_L_TestCapability(OGRLayerH layer, const char *name)
OGRFeatureDefnH OGR_L_GetLayerDefn(OGRLayerH layer)
OGRFeatureH OGR_L_GetNextFeature(OGRLayerH layer)
OGRFeatureH OGR_L_GetFeature(OGRLayerH layer, int nFeatureId)
void OGR_L_ResetReading(OGRLayerH layer)
OGRErr OGR_L_SetAttributeFilter(OGRLayerH hLayer, const char* pszQuery)
OGRErr OGR_L_SetNextByIndex(OGRLayerH layer, int nIndex)
Expand Down
2 changes: 2 additions & 0 deletions pyogrio/geopandas.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def read_dataframe(
max_features=None,
where=None,
bbox=None,
fids=None,
):
"""Read from an OGR data source to a GeoPandas GeoDataFrame or Pandas DataFrame.
If the data source does not have a geometry column or `read_geometry` is False,
Expand Down Expand Up @@ -90,6 +91,7 @@ def read_dataframe(
max_features=max_features,
where=where,
bbox=bbox,
fids=fids,
)

columns = meta["fields"].tolist()
Expand Down
2 changes: 2 additions & 0 deletions pyogrio/raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def read(
max_features=None,
where=None,
bbox=None,
fids=None,
):
"""Read OGR data source.
Expand Down Expand Up @@ -96,6 +97,7 @@ def read(
max_features=max_features or 0,
where=where,
bbox=bbox,
fids=fids,
)


Expand Down

0 comments on commit ba804ce

Please sign in to comment.