From 2f943f57618debe3045c35d9494d3b18cef67918 Mon Sep 17 00:00:00 2001 From: edzer Date: Sat, 11 May 2024 22:52:08 +0200 Subject: [PATCH] closes #37 --- NAMESPACE | 1 + NEWS.md | 4 ++++ R/RcppExports.R | 4 ++++ R/geohash.R | 19 +++++++++++++++++++ configure | 2 +- configure.ac | 2 +- man/st_geohash.Rd | 12 ++++++++++++ src/RcppExports.cpp | 13 +++++++++++++ src/lwgeom.cpp | 18 ++++++++++++++++++ 9 files changed, 73 insertions(+), 2 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 4029e30..e484e9a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -42,6 +42,7 @@ export(st_geod_distance) export(st_geod_length) export(st_geod_segmentize) export(st_geohash) +export(st_geom_from_geohash) export(st_is_polygon_cw) export(st_linesubstring) export(st_minimum_bounding_circle) diff --git a/NEWS.md b/NEWS.md index e1ac553..244e9d9 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,7 @@ +# version 0.2-16 + +* add `st_geom_from_geohash()`; #37 + # version 0.2-15 * fix default for argument `digits` in `st_astext()` diff --git a/R/RcppExports.R b/R/RcppExports.R index c3ecf18..7b75534 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -57,6 +57,10 @@ CPL_geohash <- function(sfc, prec) { .Call('_lwgeom_CPL_geohash', PACKAGE = 'lwgeom', sfc, prec) } +CPL_bbox_from_geohash <- function(h, prec) { + .Call('_lwgeom_CPL_bbox_from_geohash', PACKAGE = 'lwgeom', h, prec) +} + CPL_lwgeom_transform <- function(sfc, p4s) { .Call('_lwgeom_CPL_lwgeom_transform', PACKAGE = 'lwgeom', sfc, p4s) } diff --git a/R/geohash.R b/R/geohash.R index 7c30332..aa8c7c8 100644 --- a/R/geohash.R +++ b/R/geohash.R @@ -12,3 +12,22 @@ st_geohash = function(x, precision = 0) { CPL_geohash(st_geometry(x), precision) } + +#' @export +#' @name st_geohash +#' @param hash character vector with geohashes +#' @param crs object of class `crs` +#' @examples +#' o = options(digits = 20) +#' st_geom_from_geohash(c('9qqj7nmxncgyy4d0dbxqz0', 'u1hzz631zyd63zwsd7zt')) +#' st_geom_from_geohash('9qqj7nmxncgyy4d0dbxqz0', 4) +#' st_geom_from_geohash('9qqj7nmxncgyy4d0dbxqz0', 10) +#' options(o) +st_geom_from_geohash = function(hash, precision = -1, crs = st_crs('OGC:CRS84')) { + stopifnot(is.character(hash), is.numeric(precision), length(precision) == 1) + m = CPL_bbox_from_geohash(hash, as.integer(precision)) + bb = matrix(m, nrow = 4) + rownames(bb) = c("xmin", "ymin", "xmax", "ymax") + bb = apply(bb, 2, sf::st_bbox, simplify = FALSE) + sf::st_set_crs(do.call(c, lapply(bb, sf::st_as_sfc)), crs) +} diff --git a/configure b/configure index ea987d9..410cf7c 100755 --- a/configure +++ b/configure @@ -3978,7 +3978,7 @@ OBJECTS="${OBJECTS} \$(OBJECTS_LIBLWGEOM)" # Must keep the leading ${CPPFLAGS} or the previous CPPFLAGS don't get saved -PKG_CPPFLAGS="${CPPFLAGS} ${PKG_CPPFLAGS} -I./liblwgeom -DHAVE_LIBGEOM_INTERNAL_H" +PKG_CPPFLAGS="${CPPFLAGS} ${PKG_CPPFLAGS} -I./liblwgeom -DHAVE_LIBLWGEOM_INTERNAL_H" # diff --git a/configure.ac b/configure.ac index 56958f5..e4f1a30 100644 --- a/configure.ac +++ b/configure.ac @@ -509,7 +509,7 @@ AC_CHECK_LIB(geos_c, GEOS_init_r, AC_SUBST([OBJECTS], ["${OBJECTS} \$(OBJECTS_LIBLWGEOM)"]) # Must keep the leading ${CPPFLAGS} or the previous CPPFLAGS don't get saved -AC_SUBST([PKG_CPPFLAGS], ["${CPPFLAGS} ${PKG_CPPFLAGS} -I./liblwgeom -DHAVE_LIBGEOM_INTERNAL_H"]) +AC_SUBST([PKG_CPPFLAGS], ["${CPPFLAGS} ${PKG_CPPFLAGS} -I./liblwgeom -DHAVE_LIBLWGEOM_INTERNAL_H"]) # # concluding substitution diff --git a/man/st_geohash.Rd b/man/st_geohash.Rd index f919b5a..8953789 100644 --- a/man/st_geohash.Rd +++ b/man/st_geohash.Rd @@ -2,14 +2,21 @@ % Please edit documentation in R/geohash.R \name{st_geohash} \alias{st_geohash} +\alias{st_geom_from_geohash} \title{compute geohash from (average) coordinates} \usage{ st_geohash(x, precision = 0) + +st_geom_from_geohash(hash, precision = -1, crs = st_crs("OGC:CRS84")) } \arguments{ \item{x}{object of class \code{sf}, \code{sfc} or \code{sfg}} \item{precision}{integer; precision (length) of geohash returned. From the liblwgeom source: ``where the precision is non-positive, a precision based on the bounds of the feature. Big features have loose precision. Small features have tight precision.''} + +\item{hash}{character vector with geohashes} + +\item{crs}{object of class `crs`} } \value{ character vector with geohashes @@ -24,4 +31,9 @@ see \url{http://geohash.org/} or \url{https://en.wikipedia.org/wiki/Geohash}. library(sf) lwgeom::st_geohash(st_sfc(st_point(c(1.5,3.5)), st_point(c(0,90))), 2) lwgeom::st_geohash(st_sfc(st_point(c(1.5,3.5)), st_point(c(0,90))), 10) +o = options(digits = 20) +st_geom_from_geohash(c('9qqj7nmxncgyy4d0dbxqz0', 'u1hzz631zyd63zwsd7zt')) +st_geom_from_geohash('9qqj7nmxncgyy4d0dbxqz0', 4) +st_geom_from_geohash('9qqj7nmxncgyy4d0dbxqz0', 10) +options(o) } diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 5b2e98e..5ac45ff 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -182,6 +182,18 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } +// CPL_bbox_from_geohash +Rcpp::NumericVector CPL_bbox_from_geohash(Rcpp::CharacterVector h, int prec); +RcppExport SEXP _lwgeom_CPL_bbox_from_geohash(SEXP hSEXP, SEXP precSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::CharacterVector >::type h(hSEXP); + Rcpp::traits::input_parameter< int >::type prec(precSEXP); + rcpp_result_gen = Rcpp::wrap(CPL_bbox_from_geohash(h, prec)); + return rcpp_result_gen; +END_RCPP +} // CPL_lwgeom_transform Rcpp::List CPL_lwgeom_transform(Rcpp::List sfc, Rcpp::CharacterVector p4s); RcppExport SEXP _lwgeom_CPL_lwgeom_transform(SEXP sfcSEXP, SEXP p4sSEXP) { @@ -361,6 +373,7 @@ static const R_CallMethodDef CallEntries[] = { {"_lwgeom_CPL_split", (DL_FUNC) &_lwgeom_CPL_split, 2}, {"_lwgeom_CPL_wrap_x", (DL_FUNC) &_lwgeom_CPL_wrap_x, 3}, {"_lwgeom_CPL_geohash", (DL_FUNC) &_lwgeom_CPL_geohash, 2}, + {"_lwgeom_CPL_bbox_from_geohash", (DL_FUNC) &_lwgeom_CPL_bbox_from_geohash, 2}, {"_lwgeom_CPL_lwgeom_transform", (DL_FUNC) &_lwgeom_CPL_lwgeom_transform, 2}, {"_lwgeom_CPL_minimum_bounding_circle", (DL_FUNC) &_lwgeom_CPL_minimum_bounding_circle, 1}, {"_lwgeom_CPL_subdivide", (DL_FUNC) &_lwgeom_CPL_subdivide, 2}, diff --git a/src/lwgeom.cpp b/src/lwgeom.cpp index 1a9e8cc..ff521ba 100644 --- a/src/lwgeom.cpp +++ b/src/lwgeom.cpp @@ -137,6 +137,24 @@ Rcpp::CharacterVector CPL_geohash(Rcpp::List sfc, int prec) { return chr; } +// [[Rcpp::export]] +Rcpp::NumericVector CPL_bbox_from_geohash(Rcpp::CharacterVector h, int prec) { + + // void decode_geohash_bbox(char *geohash, double *lat, double *lon, int precision) + Rcpp::NumericVector ret(4 * h.size()); // return + double lat[2], lon[2]; + char *hash; + for (size_t i = 0; i < h.size(); i++) { + hash = h[i]; + decode_geohash_bbox(hash, lat, lon, prec); + ret[4 * i + 0] = lon[0]; + ret[4 * i + 1] = lat[0]; + ret[4 * i + 2] = lon[1]; + ret[4 * i + 3] = lat[1]; + } + return ret; +} + // [[Rcpp::export]] Rcpp::List CPL_lwgeom_transform(Rcpp::List sfc, Rcpp::CharacterVector p4s) { if (p4s.size() != 2)