Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Geometry Overhaul #48

Merged
merged 6 commits into from
May 2, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
almost done with PR
JosiahParry committed May 2, 2024

Verified

This commit was signed with the committer’s verified signature.
ajtudela Alberto Tudela
commit 61a64ae7814e5892513a9fde2577c23b4cbce2a5
3 changes: 2 additions & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -34,7 +34,8 @@ Suggests:
collapse (>= 2.0.0),
data.table,
vctrs,
testthat (>= 3.0.0)
testthat (>= 3.0.0),
jsonify
Config/testthat/edition: 3
Encoding: UTF-8
Language: en
5 changes: 5 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -12,8 +12,13 @@ export(arc_base_req)
export(arc_host)
export(arc_self_meta)
export(arc_token)
export(as_esri_features)
export(as_esri_featureset)
export(as_esri_geometry)
export(as_extent)
export(as_feature_collection)
export(as_features)
export(as_featureset)
export(as_layer)
export(as_layer_definition)
export(auth_binding)
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# arcgisutils (development version)


- All geometry conversion functions: `as_esri_geometry()`, `as_esri_features()`, `as_esri_featureset()`, `as_features()` and `as_featureset()` have been rewritten from the ground up using Rust and extendr.
- `arcgisutils` now requires Rust to build from source
- `jsonify` is moved to Suggests
- `as_geometry()` is no longer exported
- `...` argument is removed
- `auth_key()` is added to support authorization with an API key for ArcGIS Developers accounts
- `catch_error()` is a new function which parses a string and catches the error as an object. This is useful when processing multiple responses at once.
- `rbind_results()` is a new helper function that combines a list of results as efficiently as possible.
86 changes: 77 additions & 9 deletions R/esri-features-list.R
Original file line number Diff line number Diff line change
@@ -1,11 +1,80 @@
# xy <- st_sfc(st_point(c(1, 2)))
# xyz <- st_sfc(st_point(c(1, 2, 3)))
# xym <- st_sfc(st_point(c(1, 2, 3), dim = "XYM"))

# sfc_point_features_2d(xy, list())
# sfc_point_features_3d(xyz, list())
# sfc_point_features_3d(xym, list())
# NOTE 4D features cannot be supported
#' Create Esri Features
#'
#' These functions create an array of Esri Feature objects.
#' Each feature consists of a geometry and attribute field.
#' The result of `as_esri_features()` is a JSON array of Features whereas
#' `as_features()` is a list that represents the same JSON array. Using
#' `jsonify::to_json(as_features(x), unbox = TRUE)` will result in the same
#' JSON array.
#'
#' @references [API Reference](https://developers.arcgis.com/documentation/common-data-types/feature-object.htm)
#' @export
#' @rdname features
#' @param x an object of class `sf`, `data.frame`, or `sfc`.
#' @inheritParams as_esri_geometry
#' @inheritParams cli::cli_abort
#' @returns Either a scalar string or a named list.
#' @examples
#'
#' library(sf)
#' # POINT
#' # create sfg points
#' xy <- st_sfc(st_point(c(1, 2)))
#' xyz <- st_sfc(st_point(c(1, 2, 3)))
#' xym <- st_sfc(st_point(c(1, 2, 3), dim = "XYM"))
#'
#' as_esri_features(xy)
#' as_esri_features(xyz)
#' as_esri_features(xym)
#'
#' # MULTIPOINT
#' # vector to create matrix points
#' set.seed(0)
#' x <- rnorm(12)
#'
#' xy <- st_sfc(st_multipoint(matrix(x, ncol = 2)))
#' xyz <- st_sfc(st_multipoint(matrix(x, ncol = 3)))
#' xym <- st_sfc(st_multipoint(matrix(x, ncol = 3), dim = "XYM"))
#'
#' as_esri_features(xy)
#' as_esri_features(xyz)
#' as_esri_features(xym)
#'
#' # LINESTRING
#' xy <- st_sfc(st_linestring(matrix(x, ncol = 2)))
#' xyz <- st_sfc(st_linestring(matrix(x, ncol = 3)))
#' xym <- st_sfc(st_linestring(matrix(x, ncol = 3), dim = "XYM"))
#'
#' as_esri_features(xy)
#' as_esri_features(xyz)
#' as_esri_features(xym)
#'
#' # MULTILINESTRING
#' as_esri_features(st_sfc(st_multilinestring(list(xy, xy))))
#' as_esri_features(st_sfc(st_multilinestring(list(xyz, xyz))))
#' as_esri_features(st_sfc(st_multilinestring(list(xym, xym))))
#'
#' # POLYGON
#' coords <- rbind(
#' c(0, 0, 0, 1),
#' c(0, 1, 0, 1),
#' c(1, 1, 1, 1),
#' c(1, 0, 1, 1),
#' c(0, 0, 0, 1)
#' )
#'
#' xy <- st_sfc(st_polygon(list(coords[, 1:2])))
#' xyz <- st_sfc(st_polygon(list(coords[, 1:3])))
#' xym <- st_sfc(st_polygon(list(coords[, 1:3]), dim = "XYM"))
#'
#' as_esri_features(xy)
#' as_esri_features(xyz)
#' as_esri_features(xym)
#'
#' # MULTIPOLYGON
#' as_esri_features(st_sfc(st_multipolygon(list(xy[[1]], xy[[1]]))))
#' as_esri_features(st_sfc(st_multipolygon(list(xyz[[1]], xyz[[1]]))))
#' as_esri_features(st_sfc(st_multipolygon(list(xym[[1]], xym[[1]]))))
as_features <- function(x, crs = sf::st_crs(x), call = rlang::caller_env()) {
# class check
valid_sfg_classes <- c(
@@ -34,7 +103,6 @@ as_features <- function(x, crs = sf::st_crs(x), call = rlang::caller_env()) {
)
}


as_features_sfc <- function(x, crs = NULL, call = rlang::caller_env()) {
# class check
valid_sfg_classes <- c(
10 changes: 2 additions & 8 deletions R/esri-features-string.R
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
# xy <- st_sfc(st_point(c(1, 2)))
# xyz <- st_sfc(st_point(c(1, 2, 3)))
# xym <- st_sfc(st_point(c(1, 2, 3), dim = "XYM"))

# sfc_point_features_2d(xy, list())
# sfc_point_features_3d(xyz, list())
# sfc_point_features_3d(xym, list())
# NOTE 4D features cannot be supported
#' @rdname features
#' @export
as_esri_features <- function(x, crs = sf::st_crs(x), call = rlang::caller_env()) {
# class check
valid_sfg_classes <- c(
71 changes: 71 additions & 0 deletions R/esri-featureset-list.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,74 @@
#' Create Esri FeatureSet Objects
#'
#' These functions create an Esri FeatureSet object. A FeatureSet contains an inner array
#' of features as well as additional metadata about the the collection such as the
#' geometry type, spatial reference, and object ID field.
#'
#' @inheritParams as_esri_features
#' @export
#' @rdname featureset
#' @references [API Reference](https://developers.arcgis.com/documentation/common-data-types/featureset-object.htm)
#' @examples
#'
#' library(sf)
#' # POINT
#' # create sfg points
#' xy <- st_sfc(st_point(c(1, 2)))
#' xyz <- st_sfc(st_point(c(1, 2, 3)))
#' xym <- st_sfc(st_point(c(1, 2, 3), dim = "XYM"))
#'
#' as_esri_featureset(xy)
#' as_esri_featureset(xyz)
#' as_esri_featureset(xym)
#'
#' # MULTIPOINT
#' # vector to create matrix points
#' set.seed(0)
#' x <- rnorm(12)
#'
#' xy <- st_sfc(st_multipoint(matrix(x, ncol = 2)))
#' xyz <- st_sfc(st_multipoint(matrix(x, ncol = 3)))
#' xym <- st_sfc(st_multipoint(matrix(x, ncol = 3), dim = "XYM"))
#'
#' as_esri_featureset(xy)
#' as_esri_featureset(xyz)
#' as_esri_featureset(xym)
#'
#' # LINESTRING
#' xy <- st_sfc(st_linestring(matrix(x, ncol = 2)))
#' xyz <- st_sfc(st_linestring(matrix(x, ncol = 3)))
#' xym <- st_sfc(st_linestring(matrix(x, ncol = 3), dim = "XYM"))
#'
#' as_esri_featureset(xy)
#' as_esri_featureset(xyz)
#' as_esri_featureset(xym)
#'
#' # MULTILINESTRING
#' as_esri_featureset(st_sfc(st_multilinestring(list(xy, xy))))
#' as_esri_featureset(st_sfc(st_multilinestring(list(xyz, xyz))))
#' as_esri_featureset(st_sfc(st_multilinestring(list(xym, xym))))
#'
#' # POLYGON
#' coords <- rbind(
#' c(0, 0, 0, 1),
#' c(0, 1, 0, 1),
#' c(1, 1, 1, 1),
#' c(1, 0, 1, 1),
#' c(0, 0, 0, 1)
#' )
#'
#' xy <- st_sfc(st_polygon(list(coords[, 1:2])))
#' xyz <- st_sfc(st_polygon(list(coords[, 1:3])))
#' xym <- st_sfc(st_polygon(list(coords[, 1:3]), dim = "XYM"))
#'
#' as_esri_featureset(xy)
#' as_esri_featureset(xyz)
#' as_esri_featureset(xym)
#'
#' # MULTIPOLYGON
#' as_esri_featureset(st_sfc(st_multipolygon(list(xy[[1]], xy[[1]]))))
#' as_esri_featureset(st_sfc(st_multipolygon(list(xyz[[1]], xyz[[1]]))))
#' as_esri_featureset(st_sfc(st_multipolygon(list(xym[[1]], xym[[1]]))))
as_featureset <- function(x, crs = sf::st_crs(x), call = rlang::caller_env()) {
# class check
valid_sfg_classes <- c(
2 changes: 2 additions & 0 deletions R/esri-featureset-string.R
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#' @export
#' @rdname featureset
as_esri_featureset <- function(x, crs = sf::st_crs(x), call = rlang::caller_env()) {
# class check
valid_sfg_classes <- c(
11 changes: 9 additions & 2 deletions R/esri-geometry.R
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#' Create Esri JSON Geometry Objects
#'
#' `as_esri_geometry()` converts an `sfg` object to a EsriJSON Geometry object as a string.
#'
#' See [`as_featureset()`] and [`as_features()`] for converting `sfc` and `sf` objects into EsriJSON.
#'
#' @param x an object of class `sfg`. Must be one of `"POINT"`, `"MULTIPOINT"`, `"LINESTRING"`, `"MULTILINESTRING"`, `"POLYGON"`, or `"MULTIPOLYGON"`.
#' @param crs an object of class `crs`.
#' @param call an environment or call object as such as created with `rlang::caller_env()`.
#' @param crs the coordinate reference system. It must be interpretable by [`sf::st_crs()`].
#' @inheritParams cli::cli_abort
#' @returns a scalar string
#' @references [API Reference](https://developers.arcgis.com/documentation/common-data-types/geometry-objects.htm)
#' @examples
#' library(sf)
#' # POINT
@@ -73,6 +79,7 @@
#' as_esri_geometry(st_multipolygon(list(xyz, xyz)))
#' as_esri_geometry(st_multipolygon(list(xym, xym)))
#' as_esri_geometry(st_multipolygon(list(xyzm, xyzm)))
#' @export
as_esri_geometry <- function(x, crs = NULL, call = rlang::caller_env()) {
sr <- validate_crs(crs)[[1]] %||% list()

15 changes: 10 additions & 5 deletions README.Rmd
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
output: github_document
format: gfm
---

<!-- badges: start -->
@@ -18,19 +19,23 @@ knitr::opts_chunk$set(

# arcgisutils

arcgisutils is designed as the backbone of the [`{arcgis}`](https://github.com/r-arcgis/arcgis) meta-package.

arcgisutils is a developer oriented package that provides the basic functions to build R packages that work with ArcGIS Location Services. It provides functionality for authorization, Esri JSON construction and parsing, as well as other utilities pertaining to geometry and Esri type conversions.

## Installation

You can install the development version of arcgisutils from [GitHub](https://github.com/) with:
Install arcgisutils from CRAN.

``` r
# install.packages("remotes")
remotes::install_github("R-ArcGIS/arcgisutils")
install.packages("arcgisutils", repos = "https://r-arcgis.r-universe.dev")
```

arcgisutils is designed as the backbone of the package [`{arcgislayers}`](https://github.com/r-arcgis/arcgislayers) and other planned location services packages.
Or, you can install the development version of arcgisutils [r-universe](https://r-arcgis.r-universe.dev/) with:

``` r
install.packages("arcgisutils", repos = "https://r-arcgis.r-universe.dev")
```

### Authorization

@@ -68,7 +73,7 @@ The function `arc_base_req()` is used to create a standardized `httr2` request o
```{r}
host <- arc_host() # use arcgis.com by default

arc_base_req(host)
arc_base_req(host)
```

### Esri JSON
Loading