Skip to content

Commit

Permalink
Add is_empty item to output of wk_meta() (#199)
Browse files Browse the repository at this point in the history
* add empty column to handler

* docs
  • Loading branch information
paleolimbot authored Oct 7, 2023
1 parent d6db1c4 commit 3fa6d67
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 21 deletions.
3 changes: 3 additions & 0 deletions R/meta.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
#' Note that coordinate values may not have been rounded; the grid
#' size only refers to the level of detail with which they should
#' be interpreted.
#' - `is_empty`: `TRUE` if there is at least one non-empty coordinate.
#' For the purposes of this value, a non-empty coordinate is one that
#' contains at least one value that is not `NA` or `NaN`.
#'
#' @export
#'
Expand Down
3 changes: 3 additions & 0 deletions man/wk_meta.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 48 additions & 6 deletions src/meta-handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,20 @@ typedef struct {
SEXP result;
R_xlen_t result_size;
R_xlen_t feat_id;
int is_root;
int coord_size;
} meta_handler_t;

SEXP meta_handler_alloc_result(R_xlen_t size) {
const char* names[] = {"geometry_type", "size", "has_z", "has_m", "srid", "precision", ""};
const char* names[] = {"geometry_type", "size", "has_z", "has_m", "srid", "precision", "is_empty", ""};
SEXP result = PROTECT(Rf_mkNamed(VECSXP, names));
SET_VECTOR_ELT(result, 0, Rf_allocVector(INTSXP, size));
SET_VECTOR_ELT(result, 1, Rf_allocVector(INTSXP, size));
SET_VECTOR_ELT(result, 2, Rf_allocVector(LGLSXP, size));
SET_VECTOR_ELT(result, 3, Rf_allocVector(LGLSXP, size));
SET_VECTOR_ELT(result, 4, Rf_allocVector(INTSXP, size));
SET_VECTOR_ELT(result, 5, Rf_allocVector(REALSXP, size));
SET_VECTOR_ELT(result, 6, Rf_allocVector(LGLSXP, size));

UNPROTECT(1);
return result;
Expand All @@ -42,13 +45,15 @@ SEXP meta_handler_realloc_result(SEXP result, R_xlen_t new_size) {
memcpy(LOGICAL(VECTOR_ELT(new_result, 3)), LOGICAL(VECTOR_ELT(result, 3)), sizeof(int) * size_cpy);
memcpy(INTEGER(VECTOR_ELT(new_result, 4)), INTEGER(VECTOR_ELT(result, 4)), sizeof(int) * size_cpy);
memcpy(REAL(VECTOR_ELT(new_result, 5)), REAL(VECTOR_ELT(result, 5)), sizeof(double) * size_cpy);
memcpy(LOGICAL(VECTOR_ELT(new_result, 6)), LOGICAL(VECTOR_ELT(result, 6)), sizeof(int) * size_cpy);

UNPROTECT(1);
return new_result;
}

static inline void meta_handler_result_append(meta_handler_t* data, int geometry_type, int size,
int has_z, int has_m, int srid, double precision) {
int has_z, int has_m, int srid, double precision,
int is_empty) {
if (data->feat_id >= data->result_size) {
SEXP new_result = PROTECT(meta_handler_realloc_result(data->result, data->feat_id * 2 + 1));
R_ReleaseObject(data->result);
Expand All @@ -64,6 +69,7 @@ static inline void meta_handler_result_append(meta_handler_t* data, int geometry
LOGICAL(VECTOR_ELT(data->result, 3))[data->feat_id] = has_m;
INTEGER(VECTOR_ELT(data->result, 4))[data->feat_id] = srid;
REAL(VECTOR_ELT(data->result, 5))[data->feat_id] = precision;
LOGICAL(VECTOR_ELT(data->result, 6))[data->feat_id] = is_empty;
data->feat_id++;
}

Expand Down Expand Up @@ -91,11 +97,17 @@ int meta_handler_vector_start(const wk_vector_meta_t* meta, void* handler_data)
int meta_handler_feature_start(const wk_vector_meta_t* meta, R_xlen_t feat_id, void* handler_data) {
meta_handler_t* data = (meta_handler_t*) handler_data;
data->feat_id = feat_id;
data->is_root = 1;
return WK_CONTINUE;
}

int meta_handler_geometry_start(const wk_meta_t* meta, uint32_t part_id, void* handler_data) {
meta_handler_t* data = (meta_handler_t*) handler_data;
if (!data->is_root) {
return WK_CONTINUE;
}

data->is_root = 0;

int result_size;
if (meta->size == WK_SIZE_UNKNOWN) {
Expand All @@ -111,16 +123,41 @@ int meta_handler_geometry_start(const wk_meta_t* meta, uint32_t part_id, void* h
result_srid = meta->srid;
}

int has_z = (meta->flags & WK_FLAG_HAS_Z) != 0;
int has_m = (meta->flags & WK_FLAG_HAS_M) != 0;
data->coord_size = 2 + has_z + has_m;

meta_handler_result_append(
data,
meta->geometry_type,
result_size,
(meta->flags & WK_FLAG_HAS_Z) != 0,
(meta->flags & WK_FLAG_HAS_M) != 0,
has_z,
has_m,
result_srid,
meta->precision
meta->precision,
// Empty unless proven otherwise
1
);

return WK_CONTINUE;
}

int meta_handler_coord(const wk_meta_t* meta, const double* coord, uint32_t coord_id,
void* handler_data) {
meta_handler_t* data = (meta_handler_t*) handler_data;

for (int i = 0; i < data->coord_size; i++) {
if (!ISNA(coord[i]) && !ISNAN(coord[i])) {
// Not empty!
LOGICAL(VECTOR_ELT(data->result, 6))[data->feat_id - 1] = 0;
return WK_ABORT_FEATURE;
}
}

return WK_CONTINUE;
}

int meta_handler_geometry_end(const wk_meta_t* meta, uint32_t part_id, void* handler_data) {
return WK_ABORT_FEATURE;
}

Expand All @@ -133,7 +170,8 @@ int meta_handler_null_feature(void* handler_data) {
NA_LOGICAL,
NA_LOGICAL,
NA_INTEGER,
NA_REAL
NA_REAL,
NA_LOGICAL
);

return WK_ABORT_FEATURE;
Expand Down Expand Up @@ -175,6 +213,8 @@ SEXP wk_c_meta_handler_new(void) {
handler->feature_start = &meta_handler_feature_start;
handler->null_feature = &meta_handler_null_feature;
handler->geometry_start = &meta_handler_geometry_start;
handler->coord = &meta_handler_coord;
handler->geometry_end = &meta_handler_geometry_end;
handler->vector_end = &meta_handler_vector_end;
handler->deinitialize = &meta_handler_deinitialize;
handler->finalizer = &meta_handler_finalize;
Expand All @@ -185,6 +225,8 @@ SEXP wk_c_meta_handler_new(void) {
Rf_error("Failed to alloc handler data"); // # nocov
}
data->feat_id = 0;
data->is_root = 1;
data->coord_size = 2;
data->result = R_NilValue;
handler->handler_data = data;

Expand Down
33 changes: 18 additions & 15 deletions tests/testthat/test-meta.R
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@

test_that("wk_meta() works", {
expect_identical(
wk_meta(wkt(c("POINT (1 2)", NA))),
wk_meta(wkt(c("POINT (1 2)", "POINT EMPTY", NA))),
data.frame(
geometry_type = c(1L, NA_integer_),
size = c(NA_integer_, NA_integer_),
has_z = c(FALSE, NA),
has_m = c(FALSE, NA),
srid = c(NA_integer_, NA_integer_),
precision = c(0, NA_integer_)
geometry_type = c(1L, 1L, NA_integer_),
size = c(NA_integer_, 0L, NA_integer_),
has_z = c(FALSE, FALSE, NA),
has_m = c(FALSE, FALSE, NA),
srid = c(NA_integer_, NA_integer_, NA_integer_),
precision = c(0, 0, NA_integer_),
is_empty = c(FALSE, TRUE, NA)
)
)

expect_identical(
wk_meta(as_wkb(c("POINT (1 2)", NA))),
wk_meta(as_wkb(c("POINT (1 2)", "POINT EMPTY", NA))),
data.frame(
geometry_type = c(1L, NA_integer_),
size = c(1L, NA_integer_),
has_z = c(FALSE, NA),
has_m = c(FALSE, NA),
srid = c(NA_integer_, NA_integer_),
precision = c(0, NA_integer_)
geometry_type = c(1L, 1L, NA_integer_),
size = c(1L, 1L, NA_integer_),
has_z = c(FALSE, FALSE, NA),
has_m = c(FALSE, FALSE, NA),
srid = c(NA_integer_, NA_integer_, NA_integer_),
precision = c(0, 0, NA_integer_),
is_empty = c(FALSE, TRUE, NA)
)
)

Expand All @@ -32,7 +34,8 @@ test_that("wk_meta() works", {
has_z = c(FALSE, NA),
has_m = c(FALSE, NA),
srid = c(1234L, NA_integer_),
precision = c(0, NA_integer_)
precision = c(0, NA_integer_),
is_empty = c(FALSE, NA)
)
)
})
Expand Down

0 comments on commit 3fa6d67

Please sign in to comment.