├── .Rbuildignore ├── .covrignore ├── .gitattributes ├── .github └── workflows │ ├── R-CMD-check.yaml │ ├── pkgdown.yaml │ ├── rhub.yaml │ └── test-coverage.yaml ├── DESCRIPTION ├── Makefile ├── NAMESPACE ├── NEWS.md ├── R ├── api_call.R ├── api_key.R ├── directions.R ├── doc_utils.R ├── elevation.R ├── export.R ├── geocode.R ├── isochrones.R ├── leaflet.R ├── matrix.R ├── optimization.R ├── pois.R ├── profiles.R ├── snap.R ├── utils.R └── zzz.R ├── README.Rmd ├── README.md ├── codecov.yml ├── inst ├── WORDLIST └── schema │ ├── LICENSE.md │ ├── README.md │ └── geojson.json ├── man-roxygen ├── author.R ├── param-common.R ├── param-coordinates.R ├── param-profile.R ├── return-parsed.R ├── return-sf.R ├── return-text.R └── return.R ├── man ├── fitBBox.Rd ├── ors_api_key.Rd ├── ors_directions.Rd ├── ors_elevation.Rd ├── ors_export.Rd ├── ors_geocode.Rd ├── ors_isochrones.Rd ├── ors_matrix.Rd ├── ors_optimization.Rd ├── ors_pois.Rd ├── ors_profile.Rd ├── ors_snap.Rd └── print.ors_api.Rd ├── pkgdown └── extra.css ├── references.Rmd ├── references.bib ├── references.csl ├── tests ├── testthat.R └── testthat │ ├── helpers.R │ ├── mock_gpx.xml │ ├── print.txt │ ├── test-api_key.R │ ├── test-call_api.R │ ├── test-leaflet.R │ ├── test-print.R │ ├── test-query.R │ └── test-response.R ├── update_web.sh └── vignettes └── openrouteservice.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^man-roxygen$ 4 | ^README\.Rmd$ 5 | ^references.*$ 6 | ^Makefile$ 7 | ^pkgdown$ 8 | ^docs$ 9 | ^update_web\.sh$ 10 | ^codecov\.yml$ 11 | ^\.covrignore$ 12 | ^appveyor\.yml$ 13 | ^inst/WORDLIST 14 | ^articles$ 15 | ^resources$ 16 | ^\.github$ 17 | -------------------------------------------------------------------------------- /.covrignore: -------------------------------------------------------------------------------- 1 | R/doc_utils.R 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | Makefile linguist-detectable=false 2 | update_web.sh linguist-detectable=false 3 | pkgdown/extra.css linguist-detectable=false 4 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macos-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 24 | - {os: ubuntu-latest, r: 'release'} 25 | - {os: ubuntu-latest, r: 'oldrel-1'} 26 | 27 | env: 28 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 29 | ORS_API_KEY: ${{ secrets.ORS_API_KEY }} 30 | R_KEEP_PKG_SOURCE: yes 31 | 32 | steps: 33 | - uses: actions/checkout@v3 34 | 35 | - uses: r-lib/actions/setup-pandoc@v2 36 | 37 | - uses: r-lib/actions/setup-r@v2 38 | with: 39 | r-version: ${{ matrix.config.r }} 40 | http-user-agent: ${{ matrix.config.http-user-agent }} 41 | use-public-rspm: true 42 | 43 | - uses: r-lib/actions/setup-r-dependencies@v2 44 | with: 45 | extra-packages: any::rcmdcheck 46 | needs: check 47 | 48 | - uses: r-lib/actions/check-r-package@v2 49 | with: 50 | upload-snapshots: true 51 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown 13 | 14 | jobs: 15 | pkgdown: 16 | runs-on: ubuntu-latest 17 | # Only restrict concurrency for non-PR jobs 18 | concurrency: 19 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 20 | env: 21 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 22 | ORS_API_KEY: ${{ secrets.ORS_API_KEY }} 23 | permissions: 24 | contents: write 25 | steps: 26 | - uses: actions/checkout@v3 27 | 28 | - uses: r-lib/actions/setup-pandoc@v2 29 | 30 | - uses: r-lib/actions/setup-r@v2 31 | with: 32 | use-public-rspm: true 33 | 34 | - uses: r-lib/actions/setup-r-dependencies@v2 35 | with: 36 | extra-packages: any::pkgdown, local::. 37 | needs: website 38 | 39 | - name: Build site 40 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 41 | shell: Rscript {0} 42 | 43 | - name: Deploy to GitHub pages 🚀 44 | if: github.event_name != 'pull_request' 45 | uses: JamesIves/github-pages-deploy-action@v4.4.1 46 | with: 47 | clean: false 48 | branch: gh-pages 49 | folder: docs 50 | -------------------------------------------------------------------------------- /.github/workflows/rhub.yaml: -------------------------------------------------------------------------------- 1 | # R-hub's generic GitHub Actions workflow file. It's canonical location is at 2 | # https://github.com/r-hub/actions/blob/v1/workflows/rhub.yaml 3 | # You can update this file to a newer version using the rhub2 package: 4 | # 5 | # rhub::rhub_setup() 6 | # 7 | # It is unlikely that you need to modify this file manually. 8 | 9 | name: R-hub 10 | run-name: "${{ github.event.inputs.id }}: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }}" 11 | 12 | on: 13 | workflow_dispatch: 14 | inputs: 15 | config: 16 | description: 'A comma separated list of R-hub platforms to use.' 17 | type: string 18 | default: 'linux,windows,macos' 19 | name: 20 | description: 'Run name. You can leave this empty now.' 21 | type: string 22 | id: 23 | description: 'Unique ID. You can leave this empty now.' 24 | type: string 25 | 26 | jobs: 27 | 28 | setup: 29 | runs-on: ubuntu-latest 30 | outputs: 31 | containers: ${{ steps.rhub-setup.outputs.containers }} 32 | platforms: ${{ steps.rhub-setup.outputs.platforms }} 33 | 34 | steps: 35 | # NO NEED TO CHECKOUT HERE 36 | - uses: r-hub/actions/setup@v1 37 | with: 38 | config: ${{ github.event.inputs.config }} 39 | id: rhub-setup 40 | 41 | linux-containers: 42 | needs: setup 43 | if: ${{ needs.setup.outputs.containers != '[]' }} 44 | runs-on: ubuntu-latest 45 | name: ${{ matrix.config.label }} 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | config: ${{ fromJson(needs.setup.outputs.containers) }} 50 | container: 51 | image: ${{ matrix.config.container }} 52 | 53 | steps: 54 | - uses: r-hub/actions/checkout@v1 55 | - uses: r-hub/actions/platform-info@v1 56 | with: 57 | token: ${{ secrets.RHUB_TOKEN }} 58 | job-config: ${{ matrix.config.job-config }} 59 | - uses: r-hub/actions/setup-deps@v1 60 | with: 61 | token: ${{ secrets.RHUB_TOKEN }} 62 | job-config: ${{ matrix.config.job-config }} 63 | - uses: r-hub/actions/run-check@v1 64 | with: 65 | token: ${{ secrets.RHUB_TOKEN }} 66 | job-config: ${{ matrix.config.job-config }} 67 | 68 | other-platforms: 69 | needs: setup 70 | if: ${{ needs.setup.outputs.platforms != '[]' }} 71 | runs-on: ${{ matrix.config.os }} 72 | name: ${{ matrix.config.label }} 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | config: ${{ fromJson(needs.setup.outputs.platforms) }} 77 | 78 | env: 79 | ORS_API_KEY: ${{ secrets.ORS_API_KEY }} 80 | 81 | steps: 82 | - uses: r-hub/actions/checkout@v1 83 | - uses: r-hub/actions/setup-r@v1 84 | with: 85 | job-config: ${{ matrix.config.job-config }} 86 | token: ${{ secrets.RHUB_TOKEN }} 87 | - uses: r-hub/actions/platform-info@v1 88 | with: 89 | token: ${{ secrets.RHUB_TOKEN }} 90 | job-config: ${{ matrix.config.job-config }} 91 | - uses: r-hub/actions/setup-deps@v1 92 | with: 93 | job-config: ${{ matrix.config.job-config }} 94 | token: ${{ secrets.RHUB_TOKEN }} 95 | - uses: r-hub/actions/run-check@v1 96 | with: 97 | job-config: ${{ matrix.config.job-config }} 98 | token: ${{ secrets.RHUB_TOKEN }} 99 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage 10 | 11 | jobs: 12 | test-coverage: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | with: 22 | use-public-rspm: true 23 | 24 | - uses: r-lib/actions/setup-r-dependencies@v2 25 | with: 26 | extra-packages: any::covr 27 | needs: coverage 28 | 29 | - name: Test coverage 30 | run: | 31 | covr::codecov( 32 | quiet = FALSE, 33 | clean = FALSE, 34 | install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") 35 | ) 36 | shell: Rscript {0} 37 | 38 | - name: Show testthat output 39 | if: always() 40 | run: | 41 | ## -------------------------------------------------------------------- 42 | find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true 43 | shell: bash 44 | 45 | - name: Upload test results 46 | if: failure() 47 | uses: actions/upload-artifact@v3 48 | with: 49 | name: coverage-test-failures 50 | path: ${{ runner.temp }}/package 51 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: openrouteservice 2 | Title: An 'openrouteservice' API Client 3 | Version: 0.6.2 4 | Authors@R: c( 5 | person("Heidelberg Institute for Geoinformation Technology (HeiGIT) gGmbH", role = "cph"), 6 | person(c("Andrzej", "K."), "Oleś", email = "andrzej.oles@gmail.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0285-2787")) 7 | ) 8 | Description: The client streamlines access to the services provided by . 9 | It allows you to painlessly query for directions, isochrones, time-distance matrices, geocoding, elevation, points of interest, and more. 10 | URL: https://github.com/GIScience/openrouteservice-r 11 | BugReports: https://github.com/GIScience/openrouteservice-r/issues 12 | Imports: geojsonsf, httr, jsonlite, jsonvalidate, keyring, leaflet, utils, V8, xml2 13 | Suggests: covr, ggplot2, googlePolylines, lwgeom, knitr, mapview, pkgdown, RColorBrewer, rmarkdown, roxygen2, sf, testthat, units 14 | License: Apache License 2.0 15 | Encoding: UTF-8 16 | VignetteBuilder: knitr 17 | Roxygen: list(markdown = TRUE) 18 | RoxygenNote: 7.3.2 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PKGNAME := $(shell grep '^Package:' DESCRIPTION | sed -E 's/^Package:[[:space:]]+//') 2 | PKGVER := $(shell grep '^Version:' DESCRIPTION | sed -E 's/^Version:[[:space:]]+//') 3 | PKGDIR = $(shell basename $(dir $(realpath $(firstword $(MAKEFILE_LIST))))) 4 | 5 | RSCRIPT = Rscript --vanilla 6 | 7 | %.md: %.Rmd 8 | ${RSCRIPT} -e 'rmarkdown::render("$<")' 9 | 10 | README.md: vignettes/${PKGNAME}.Rmd NEWS.md references.md 11 | 12 | references.md: references.bib 13 | 14 | readme: README.md 15 | 16 | document: 17 | ${RSCRIPT} -e "devtools::document()" 18 | 19 | build: document readme 20 | cd ..; R CMD build ${PKGDIR} 21 | 22 | install: build 23 | R CMD INSTALL ../${PKGNAME}_${PKGVER}.tar.gz 24 | 25 | check: build 26 | cd ..; R CMD check --as-cran --no-manual ${PKGNAME}_${PKGVER}.tar.gz 27 | 28 | website: 29 | ${RSCRIPT} -e "pkgdown::build_site()" 30 | 31 | clean: 32 | ${RSCRIPT} -e "pkgdown::clean_site()" 33 | 34 | spellcheck: 35 | ${RSCRIPT} -e "devtools::spell_check()" 36 | 37 | publish: install check clean website spellcheck 38 | 39 | gh_pages: publish 40 | ./update_web.sh 41 | 42 | .PHONY: readme document build install check website clean publish spellcheck 43 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(print,ors_api) 4 | export(fitBBox) 5 | export(jobs) 6 | export(ors_api_key) 7 | export(ors_directions) 8 | export(ors_elevation) 9 | export(ors_export) 10 | export(ors_geocode) 11 | export(ors_isochrones) 12 | export(ors_matrix) 13 | export(ors_optimization) 14 | export(ors_pois) 15 | export(ors_profile) 16 | export(ors_snap) 17 | export(vehicles) 18 | importFrom(V8,v8) 19 | importFrom(geojsonsf,geojson_sf) 20 | importFrom(httr,GET) 21 | importFrom(httr,POST) 22 | importFrom(httr,accept) 23 | importFrom(httr,add_headers) 24 | importFrom(httr,content) 25 | importFrom(httr,http_condition) 26 | importFrom(httr,http_error) 27 | importFrom(httr,http_type) 28 | importFrom(httr,modify_url) 29 | importFrom(httr,parse_url) 30 | importFrom(httr,status_code) 31 | importFrom(httr,user_agent) 32 | importFrom(httr,verbose) 33 | importFrom(jsonlite,fromJSON) 34 | importFrom(jsonlite,toJSON) 35 | importFrom(jsonlite,validate) 36 | importFrom(jsonvalidate,json_validator) 37 | importFrom(keyring,key_get) 38 | importFrom(keyring,key_list) 39 | importFrom(keyring,key_set_with_value) 40 | importFrom(leaflet,fitBounds) 41 | importFrom(utils,str) 42 | importFrom(utils,type.convert) 43 | importFrom(xml2,read_xml) 44 | importFrom(xml2,xml_validate) 45 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # openrouteservice 0.6.0 2 | 3 | ## NEW FEATURES 4 | 5 | - Enable export endpoint. 6 | 7 | # openrouteservice 0.5.2 8 | 9 | ## NEW FEATURES 10 | 11 | - sf output for snapping. 12 | 13 | # openrouteservice 0.5.1 14 | 15 | ## BUG FIXES 16 | 17 | - sf output for POIs endpoint (#81) 18 | 19 | # openrouteservice 0.5.0 20 | 21 | ## NEW FEATURES 22 | 23 | - Enable snap endpoint. 24 | 25 | # openrouteservice 0.4.0 26 | 27 | ## NEW FEATURES 28 | 29 | - Enable optimization endpoint. 30 | 31 | # openrouteservice 0.3.3 32 | 33 | ## BUG FIXES 34 | 35 | - Fixed resolving of URL paths to endpoints. 36 | 37 | # openrouteservice 0.3.2 38 | 39 | ## NEW FEATURES 40 | 41 | - More descriptive messages for API response errors. 42 | 43 | # openrouteservice 0.3.1 44 | 45 | ## NEW FEATURES 46 | 47 | - Arguments corresponding to array parameters don't need to be wrapped in `I()`. 48 | 49 | # openrouteservice 0.2.7 50 | 51 | ## NEW FEATURES 52 | 53 | - `ors_elevation()` now accepts point coordinates in matrix form. 54 | 55 | ## BUG FIXES 56 | 57 | - `ors_elevation()` does not issue a message on missing encoding anymore. 58 | 59 | # openrouteservice 0.2.6 60 | 61 | ## NEW FEATURES 62 | 63 | - `ors_pois()` gains `sf` output. 64 | 65 | # openrouteservice 0.2.5 66 | 67 | ## NEW FEATURES 68 | 69 | - Improved `ors_elevation()` response handling. 70 | 71 | # openrouteservice 0.2.4 72 | 73 | ## NEW FEATURES 74 | 75 | - `ors_directions()`, `ors_isochrones()`, `ors_elevation()` and `ors_geocode()` 76 | can now output `sf` objects (#42). 77 | 78 | # openrouteservice 0.2.3 79 | 80 | ## NEW FEATURES 81 | 82 | - `ors_isochrones()` now accepts `locations` provided as `data.frame` (#38). 83 | 84 | # openrouteservice 0.2.2 85 | 86 | ## BUG FIXES 87 | 88 | - Improve handling of paths to openrouteservice endpoints (#46). 89 | 90 | # openrouteservice 0.2.1 91 | 92 | ## NEW FEATURES 93 | 94 | - `ors_elevation()` example added to vignette. 95 | 96 | # openrouteservice 0.2.0 97 | 98 | ## NEW FEATURES 99 | 100 | - Switched to openrouteservice API v2. 101 | 102 | # openrouteservice 0.1.25 103 | 104 | ## NEW FEATURES 105 | 106 | - `ors_elevation()` provides access to the new endpoint. 107 | -------------------------------------------------------------------------------- /R/api_call.R: -------------------------------------------------------------------------------- 1 | # collapse vectors to (pipe-separated) strings 2 | collapse_vector <- function(x, collapse = "|") { 3 | if (!is.list(x) && length(x) > 1L) 4 | paste(x, collapse=collapse) 5 | else 6 | x 7 | } 8 | 9 | # encode pairs as comma-separated strings 10 | encode_pairs <- function(x) { 11 | x = unlist(x, use.names = FALSE) 12 | if ( length(x) %% 2L ) 13 | stop("Failed to encode pairs, odd number of elements") 14 | v = c(TRUE, FALSE) 15 | paste(x[v], x[!v], sep=",") 16 | } 17 | 18 | # reduce precision of numeric parameters to 6 decimal places 19 | limit_precision <- function(l, digits) { 20 | rapply(l, how="replace", f = function(x) { 21 | if ( is.numeric(x) && !is.integer(x) ) 22 | round(x, digits=digits) 23 | else 24 | x 25 | }) 26 | } 27 | 28 | #' @importFrom jsonlite toJSON 29 | api_query <- function(api_key, params = list(), collapse = "|") { 30 | ## process parameters 31 | if ( length(params) ) { 32 | digits <- getOption('openrouteservice.digits', 6L) 33 | 34 | params <- limit_precision(params, digits) 35 | 36 | # encode lists of pairs 37 | pair_params = c("locations", "coordinates", "bearings") 38 | pair_params = pair_params[pair_params %in% names(params)] 39 | 40 | if ( length(pair_params)>0L ) 41 | params[pair_params] = lapply(params[pair_params], encode_pairs) 42 | 43 | # store polygon coordinates to preserve their original structure 44 | avoid_polygons = params$options$avoid_polygons 45 | 46 | params = rapply(params, collapse_vector, how="replace", collapse=collapse) 47 | 48 | if ( !is.null(avoid_polygons) ) 49 | params$options$avoid_polygons = avoid_polygons 50 | 51 | if ( !is.null(params$options) ) 52 | params$options = toJSON(params$options, auto_unbox=TRUE, digits=digits) 53 | } 54 | 55 | c(api_key = api_key, params) 56 | } 57 | 58 | 59 | #' @importFrom httr GET POST accept modify_url user_agent status_code 60 | call_api <- function (method, args) { 61 | method <- match.fun(method) 62 | sleep_time <- 1L 63 | while (TRUE) { 64 | res <- do.call(method, args) 65 | if ( status_code(res) == 429L ) 66 | Sys.sleep( (sleep_time <- sleep_time * 2L) ) 67 | else 68 | break 69 | } 70 | res 71 | } 72 | 73 | ors_url <- function() { 74 | getOption('openrouteservice.url', "https://api.openrouteservice.org") 75 | } 76 | 77 | ors_path <- function(endpoint) { 78 | default_paths <- list ( 79 | directions = "v2/directions", 80 | isochrones = "v2/isochrones", 81 | matrix = "v2/matrix", 82 | geocode = "geocode", 83 | pois = "pois", 84 | elevation = "elevation", 85 | optimization = "optimization", 86 | snap = "v2/snap", 87 | export = "v2/export" 88 | ) 89 | if (missing(endpoint)) 90 | return(default_paths) 91 | 92 | ## path from options overrides the default 93 | path <- getOption('openrouteservice.paths')[[endpoint]] 94 | if (!is.null(path)) 95 | path 96 | else 97 | default_paths[[endpoint]] 98 | } 99 | 100 | #' @importFrom httr modify_url parse_url verbose 101 | api_call <- function(path, api_key, query = NULL, body = NULL, ..., 102 | response_format = c("json", "geojson", "gpx"), 103 | output, simplifyMatrix = TRUE) { 104 | 105 | response_format <- match.arg(response_format) 106 | 107 | endpoint <- basename(path[1L]) 108 | path[1L] <- ors_path(endpoint) 109 | 110 | ## process query params 111 | if (!is.null(query)) 112 | query <- api_query(api_key, query, collapse = ",") 113 | 114 | ## extract base path from url in order to retain it in modify_url(), see #46 115 | basepath <- parse_url(ors_url())$path 116 | basepath <- unlist(strsplit(basepath, split="/")) # removes trailing / 117 | 118 | fullpath <- paste(c(basepath, path), collapse="/") 119 | 120 | url <- modify_url(ors_url(), path = fullpath, query = query) 121 | 122 | type <- sprintf("application/%s", switch(response_format, "json", geojson="geo+json", gpx="gpx+xml")) 123 | 124 | args <- list(url = url, 125 | accept(type), 126 | user_agent("openrouteservice-r"), 127 | ..., 128 | if (isTRUE(getOption('openrouteservice.verbose'))) verbose()) 129 | 130 | method = if (is.null(body)) "GET" else "POST" 131 | 132 | ## add body and authorization header 133 | if (method=="POST") 134 | args = c(args, list(body = body, add_headers(Authorization = api_key))) 135 | 136 | res <- call_api(method, args) 137 | 138 | process_response(res, endpoint, output, simplifyMatrix) 139 | } 140 | 141 | #' @importFrom httr content http_condition http_error http_type status_code 142 | process_response <- function(res, endpoint, output, simplifyMatrix) { 143 | if (http_error(res)) { 144 | condition <- http_condition(res, "error", call = NULL) 145 | ## extract error details 146 | try(if (http_type(res)=="application/json") { 147 | err <- content(res) 148 | if (!is.null(err$error)) 149 | err <- err$error 150 | else if (!is.null(err$geocoding)) 151 | err <- paste(err$geocoding$errors, collapse = "; ") 152 | condition$message <- 153 | if (length(err) == 1L) 154 | error_message(res, err) 155 | else 156 | error_message(err$code, err$message) 157 | }, silent = TRUE) 158 | stop(condition) 159 | } 160 | 161 | format <- res$request$headers[["Accept"]] 162 | 163 | if (http_type(res) != format) 164 | stop(sprintf("API did not return %s", format), call. = FALSE) 165 | 166 | query_time <- unname(res$times["total"]) 167 | 168 | format <- switch(format, "application/gpx+xml"="xml", "json") 169 | 170 | res <- parse_content(suppressMessages(content(res, "text")), 171 | format, output, endpoint, simplifyMatrix) 172 | 173 | attr(res, "query_time") <- query_time 174 | 175 | res 176 | } 177 | 178 | error_message <- function(code, details) { 179 | msg <- sprintf("Openrouteservice API request failed\n[%s]", status_code(code)) 180 | if (!is.null(details) && nchar(details)!=0L) 181 | msg <- paste(msg, details) 182 | msg 183 | } 184 | 185 | #' @importFrom geojsonsf geojson_sf 186 | #' @importFrom jsonlite fromJSON toJSON validate 187 | #' @importFrom utils type.convert 188 | #' @importFrom xml2 read_xml xml_validate 189 | parse_content <- function (content, 190 | format = c("json", "xml"), 191 | output = c("parsed", "text", "sf"), 192 | endpoint, simplifyMatrix) { 193 | format <- match.arg(format) 194 | output <- match.arg(output) 195 | 196 | parseJSON <- function(txt, 197 | simplifyVector = TRUE, 198 | simplifyDataFrame = FALSE, 199 | simplifyMatrix = TRUE, 200 | ...) 201 | fromJSON(txt, 202 | simplifyVector = simplifyVector, 203 | simplifyDataFrame = simplifyDataFrame, 204 | simplifyMatrix = simplifyMatrix, 205 | ...) 206 | 207 | ## extract elevation geometry 208 | if (endpoint=="elevation") 209 | content <- toJSON(fromJSON(content)$geometry, auto_unbox=TRUE) 210 | 211 | ## parsed R list 212 | if (output=="parsed") { 213 | if (format=="json") { 214 | content <- parseJSON(content, simplifyMatrix = simplifyMatrix) 215 | class <- c(sprintf("ors_%s", endpoint), "ors_api", class(content)) 216 | content <- structure(content, class = class) 217 | return(content) 218 | } 219 | if (format=="xml") { 220 | content <- read_xml(content) 221 | gpx_xsd <- getOption("openrouteservice.gpx_xsd", "https://raw.githubusercontent.com/GIScience/openrouteservice-schema/master/gpx/v2/ors-gpx.xsd") 222 | xsd <- read_xml(gpx_xsd) 223 | if (!xml_validate(content, xsd)) 224 | stop("Failed to validate GPX response") 225 | return(content) 226 | } 227 | } 228 | 229 | is_geojson <- format=="json" && isTRUE(validate_geojson(content)) 230 | 231 | ## raw text output 232 | if (output=="text") { 233 | if (format=="json" && validate(content)) 234 | content <- structure(content, class = c(if (is_geojson) "geojson","json")) 235 | return(content) 236 | } 237 | 238 | if (output=="sf" && is_geojson) { 239 | res <- tryCatch(geojson_sf(content), error = function(e) stop(e$message,": ", content, call. = FALSE)) 240 | 241 | if (endpoint=="directions") { 242 | ## convert parsed properties to sf compatible data.frame 243 | properties <- lapply(parseJSON(content)$features, function(feature) { 244 | prop_list <- lapply(feature[['properties']], 245 | function(x) if (length(x) > 1L) list(x) else x) 246 | structure(prop_list, class = "data.frame", row.names = 1L) 247 | }) 248 | 249 | properties = do.call(rbind, properties) 250 | 251 | res[names(properties)] <- properties 252 | } 253 | else if (endpoint %in% c("isochrones", "pois")) { 254 | for (i in 1:length(res)) { 255 | # attempt to parse JSON strings to R objects 256 | if (is.character(res[[i]])) { 257 | res[[i]] <- lapply(res[[i]], function(x) { 258 | if (is.na(x)) 259 | NA 260 | else 261 | parseJSON(x) 262 | }) 263 | } 264 | } 265 | } 266 | 267 | # use integer indices 268 | id_cols <- c("group_index", "source_id") 269 | id_cols <- id_cols[id_cols %in% names(res)] 270 | for (name in id_cols) 271 | res[[name]] <- type.convert(res[[name]], as.is = TRUE) 272 | 273 | return(res) 274 | } 275 | 276 | stop(sprintf("Unsupported %s output for %s format.", output, format)) 277 | } 278 | 279 | #' Print a Compact Summary of the API Response 280 | #' 281 | #' `print.ors_api` uses [str][utils::str()] to compactly display the structure 282 | #' of the openrouteservice API response object. 283 | #' 284 | #' @param x object of class `ors_api`. 285 | #' @inheritParams utils::str 286 | #' @param ... further arguments passed to [str][utils::str()]. 287 | #' @return `print.ors_api` prints its argument and returns it _invisibly_. 288 | #' @importFrom utils str 289 | #' @export 290 | print.ors_api <- function(x, give.attr = FALSE, list.len = 6L, ...) { 291 | cat(sprintf("<%s>\n", class(x)[1L])) 292 | str(unclass(x), list.len = list.len, give.attr = give.attr, ...) 293 | invisible(x) 294 | } 295 | 296 | validator <- new.env() 297 | 298 | #' @importFrom jsonvalidate json_validator 299 | #' @importFrom V8 v8 300 | validate_geojson <- function(...) { 301 | validator$instance(...) 302 | } 303 | -------------------------------------------------------------------------------- /R/api_key.R: -------------------------------------------------------------------------------- 1 | #' API key management 2 | #' 3 | #' Get/set openrouteservice API key. 4 | #' 5 | #' To set the key provide it in the `key` argument. To retrieve the current 6 | #' value call the function with `key` unset. 7 | #' 8 | #' Typically the key is saved in the system credential store. Once the key is 9 | #' defined, it persists in the keyring store of the operating system so it 10 | #' doesn't need to be set again in a new R session. 11 | #' 12 | #' Internally the function uses `\link[keyring]{key_set}` and 13 | #' `\link[keyring]{key_get}`. The use of keyring package can be bypassed by 14 | #' providing the key in the environment variable ORS_API_KEY. The value from the 15 | #' environment variable takes precedence over the value stored in the system 16 | #' credential store. The default environment variable name used to retrieve the 17 | #' openrouteservice api key can be overridden by specifying it in 18 | #' `options("openrouteservice.api_key_env")`. 19 | #' 20 | #' @param key API key value provided as a character scalar 21 | #' @inheritParams keyring::key_set 22 | #' @return API Key value when called without `key`. 23 | #' @template author 24 | #' @importFrom keyring key_list key_get key_list key_set_with_value 25 | #' @export 26 | ors_api_key <- function (key, service = 'openrouteservice', username = NULL, keyring = NULL) { 27 | ## get key 28 | if ( missing(key) ) { 29 | api_key_env <- getOption("openrouteservice.api_key_env", "ORS_API_KEY") 30 | api_key_val <- Sys.getenv(api_key_env) 31 | ## api key set in environment variable takes precedence over keyring 32 | if ( nchar(api_key_val) ) 33 | api_key_val 34 | else if ( on_cran() ) 35 | NA 36 | else if ( isTRUE(grepl("^https?://api.openrouteservice.org$", ors_url())) ) 37 | tryCatch( 38 | key_get(service, username, keyring), 39 | error = function(e) 40 | stop(sprintf("API key not set.\n Get your free key at %s\n Use `ors_api_key('')` to set it", signup_url()), call. = FALSE)) 41 | } 42 | ## set key 43 | else 44 | key_set_with_value(service, username, key, keyring) 45 | } 46 | -------------------------------------------------------------------------------- /R/directions.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice Directions 2 | #' 3 | #' Get directions for different modes of transport. 4 | #' 5 | #' @template param-coordinates 6 | #' @templateVar argname coordinates 7 | #' @templateVar suffix visited in order 8 | #' @template param-profile 9 | #' @param format Response format, defaults to `"geojson"` 10 | #' @template param-common 11 | #' @templateVar dotsargs parameters 12 | #' @templateVar endpoint directions 13 | #' @template return 14 | #' @templateVar return Route between two or more locations in the selected `format` 15 | #' @template return-text 16 | #' @template return-parsed 17 | #' @template return-sf 18 | #' @examples 19 | #' # These examples might require interaction to query the local keyring, or 20 | #' # might fail due to network issues, so they are not run by default 21 | #' \dontrun{ 22 | #' coordinates <- list(c(8.34234, 48.23424), c(8.34423, 48.26424)) 23 | #' 24 | #' # simple call 25 | #' try( ors_directions(coordinates, preference="fastest") ) 26 | #' 27 | #' # customized options 28 | #' try( ors_directions(coordinates, profile="cycling-mountain", elevation=TRUE) ) 29 | #' 30 | #' # list of locations as `data.frame` output as simple features `sf` object 31 | #' locations <- data.frame(lng = c(8.34234, 8.327807, 8.34423), 32 | #' lat = c(48.23424, 48.239368, 48.26424)) 33 | #' try( ors_directions(locations, output = "sf") ) 34 | #' } 35 | #' @template author 36 | #' @export 37 | ors_directions <- function(coordinates, 38 | profile = ors_profile(), 39 | format = c('geojson', 'json', 'gpx'), 40 | ..., 41 | api_key = ors_api_key(), 42 | output = c("parsed", "text", "sf")) { 43 | 44 | ## required arguments with no default value 45 | if (missing(coordinates)) 46 | stop('Missing argument "coordinates"') 47 | 48 | ## required arguments with defaults 49 | profile <- match.arg(profile) 50 | format <- match.arg(format) 51 | output <- match.arg(output) 52 | 53 | ## request parameters 54 | names(coordinates) <- NULL 55 | body <- protect( 56 | list(coordinates = coordinates, ...), 57 | arrays = c( 58 | "attributes", 59 | "bearings", 60 | "extra_info", 61 | "radiuses", 62 | "skip_segments", 63 | "avoid_countries", 64 | "avoid_features" 65 | ) 66 | ) 67 | 68 | api_call( 69 | path = c("v2/directions", profile, format), 70 | api_key = api_key, 71 | body = body, 72 | encode = "json", 73 | response_format = format, 74 | output = output 75 | ) 76 | } 77 | -------------------------------------------------------------------------------- /R/doc_utils.R: -------------------------------------------------------------------------------- 1 | doc_url <- function(service) { 2 | url_template <- switch( 3 | service, 4 | directions = , 5 | isochrones = , 6 | matrix = , 7 | snap = , 8 | export = 9 | "https://openrouteservice.org/dev/#/api-docs/v2/%s/{profile}/post", 10 | pois = , 11 | optimization = 12 | "https://openrouteservice.org/dev/#/api-docs/%s/post", 13 | "https://openrouteservice.org/dev/#/api-docs/%s" 14 | ) 15 | sprintf(url_template, service) 16 | } 17 | 18 | doc_link <- function(service, label = service) 19 | sprintf("[%s](%s)", label, doc_url(service)) 20 | 21 | signup_url <- function (label) { 22 | url <- "https://openrouteservice.org/dev/#/signup" 23 | if (missing(label)) 24 | url 25 | else 26 | sprintf("[%s](%s)", label, url) 27 | } 28 | -------------------------------------------------------------------------------- /R/elevation.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice Elevation 2 | #' 3 | #' Get elevation data for points or lines 4 | #' 5 | #' A GeoJSON based service to query SRTM elevation for Point or LineString 2D 6 | #' geometries and return 3D geometries in various formats. 7 | #' 8 | #' @param geometry `longitude, latitude` coordinate pairs 9 | #' @param format_in input format 10 | #' @param format_out output format 11 | #' @template param-common 12 | #' @templateVar dotsargs parameters 13 | #' @templateVar endpoint elevation 14 | #' @template return 15 | #' @templateVar return 3D point or line geometry 16 | #' @template return-text 17 | #' @template return-parsed 18 | #' @template return-sf 19 | #' @examples 20 | #' # These examples might require interaction to query the local keyring, or 21 | #' # might fail due to network issues, so they are not run by default 22 | #' \dontrun{ 23 | #' # point coordinates 24 | #' coordinates <- c(13.349762, 38.11295) 25 | #' try( ors_elevation("point", coordinates) ) 26 | #' 27 | #' # geojson as input 28 | #' point <- '{ "type": "Point", "coordinates": [13.349762, 38.11295] }' 29 | #' try( ors_elevation("geojson", point) ) 30 | #' 31 | #' # line geometry returned as encoded polyline 32 | #' coordinates <- list( 33 | #' c(13.349762, 38.11295), 34 | #' c(12.638397, 37.645772) 35 | #' ) 36 | #' try( ors_elevation("polyline", coordinates, format_out = "encodedpolyline") ) 37 | #' } 38 | #' @template author 39 | #' @importFrom httr add_headers 40 | #' @export 41 | ors_elevation <- function(format_in = c("geojson", "point", "polyline", "encodedpolyline", "encodedpolyline6"), 42 | geometry, 43 | format_out = format_in, 44 | ..., 45 | api_key = ors_api_key(), 46 | output = c("parsed", "text", "sf")) { 47 | 48 | ## required arguments with no default value 49 | if (missing(format_in)) 50 | stop('Missing input format specification') 51 | if (missing(geometry)) 52 | stop('geometry') 53 | 54 | format_in <- match.arg(format_in) 55 | 56 | ## check whether geojson is a point or a line 57 | if (format_in == "geojson") { 58 | geometry <- fromJSON(geometry) 59 | input <- geometry$type 60 | } else { 61 | names(geometry) <- NULL 62 | if (format_in=="point") 63 | geometry <- as.vector(geometry) 64 | input <- format_in 65 | } 66 | 67 | endpoint <- switch(tolower(input), 68 | point = "point", 69 | polyline =, encodedpolyline =, encodedpolyline6 = "line") 70 | 71 | ## required arguments with defaults 72 | valid_formats <- switch (endpoint, 73 | point = c("point"), 74 | line = c("polyline", "encodedpolyline", "encodedpolyline6")) 75 | format_out <- match.arg(format_out, c("geojson", valid_formats)) 76 | output <- match.arg(output) 77 | 78 | body <- list(format_in = format_in, 79 | geometry = geometry, 80 | format_out = format_out, 81 | ...) 82 | 83 | api_call(path = c("elevation", endpoint), 84 | api_key = api_key, 85 | body = body, 86 | encode = "json", 87 | output = output) 88 | } 89 | -------------------------------------------------------------------------------- /R/export.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice Export 2 | #' 3 | #' Export the base graph for different modes of transport. 4 | #' 5 | #' @template param-coordinates 6 | #' @templateVar argname bbox 7 | #' @templateVar suffix defining the SW and NE corners of a rectangular area of interest 8 | #' @template param-profile 9 | #' @template param-common 10 | #' @templateVar dotsargs parameters 11 | #' @templateVar endpoint export 12 | #' @template return 13 | #' @templateVar return Lists of graph nodes and edges contained in the provided bounding box and relevant for the given routing profile. The edge property `weight` represents travel time in seconds. The response is 14 | #' @template return-text 15 | #' @template return-parsed 16 | #' @examples 17 | #' \dontrun{ 18 | #' bbox <- list( 19 | #' c(8.681495, 49.41461), 20 | #' c(8.686507, 49.41943) 21 | #' ) 22 | #' 23 | #' res <- ors_export(bbox) 24 | #' } 25 | #' @template author 26 | #' @export 27 | ors_export <- function(bbox, 28 | profile = ors_profile(), 29 | ..., 30 | api_key = ors_api_key(), 31 | output = c("parsed", "text")) { 32 | ## required arguments with no default value 33 | if (missing(bbox)) 34 | stop('Missing argument "bbox"') 35 | 36 | ## required arguments with defaults 37 | profile <- match.arg(profile) 38 | output <- match.arg(output) 39 | 40 | ## request parameters 41 | body <- list(bbox = bbox, ...) 42 | 43 | api_call( 44 | path = c("v2/export", profile), 45 | api_key = api_key, 46 | body = body, 47 | encode = "json", 48 | output = output 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /R/geocode.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice Geocoding 2 | #' 3 | #' Resolve input coordinates to addresses and vice versa. 4 | #' 5 | #' This endpoint can be used for geocoding (specified `query`) and reverse 6 | #' geocoding requests (specified `location`). Either `query` or `location` has 7 | #' to be specified for a valid request. If both parameters are specified 8 | #' location takes precedence. 9 | #' 10 | #' @param query Name of location, street address or postal code. For a 11 | #' structured geocoding request a named list of parameters. 12 | #' @param location Coordinates to be inquired provided in the form `c(longitude, 13 | #' latitude)` 14 | #' @template param-common 15 | #' @templateVar dotsargs parameters 16 | #' @templateVar endpoint geocode 17 | #' @return Geocoding: a JSON formatted list of objects corresponding to the 18 | #' search input. Reverse geocoding: the next enclosing object with an address 19 | #' tag which surrounds the given coordinate. 20 | #' @template author 21 | #' @examples 22 | #' # These examples might require interaction to query the local keyring, or 23 | #' # might fail due to network issues, so they are not run by default 24 | #' \dontrun{ 25 | #' ## locations of Heidelberg around the globe 26 | #' x <- ors_geocode("Heidelberg") 27 | #' 28 | #' ## set the number of results returned 29 | #' x <- ors_geocode("Heidelberg", size = 1) 30 | #' 31 | #' ## search within a particular country 32 | #' ors_geocode("Heidelberg", boundary.country = "DE") 33 | #' 34 | #' ## structured geocoding 35 | #' x <- ors_geocode(list(locality="Heidelberg", county="Heidelberg")) 36 | #' 37 | #' ## reverse geocoding 38 | #' location <- x$features[[1L]]$geometry$coordinates 39 | #' y <- ors_geocode(location = location, layers = "locality", size = 1) 40 | #' } 41 | #' @export 42 | ors_geocode <- function(query, 43 | location, 44 | ..., 45 | api_key = ors_api_key(), 46 | output = c("parsed", "text", "sf")) { 47 | endpoint <- 48 | if ( missing(query) ) { 49 | if ( missing(location) ) 50 | stop('Specify at least one of the arguments "query/location"') 51 | params <- list(point.lon = location[1L], point.lat = location[2L], ...) 52 | "reverse" 53 | } 54 | else { 55 | if ( length(query) > 1L ) { 56 | if ( !is.list(query) ) 57 | query <- as.list(query) 58 | params <- c(query, ...) 59 | "search/structured" 60 | } 61 | else { 62 | params <- list(text = query, ...) 63 | "search" 64 | } 65 | } 66 | 67 | output <- match.arg(output) 68 | 69 | api_call(c("geocode", endpoint), 70 | api_key = api_key, 71 | query = params, 72 | output = output) 73 | } 74 | -------------------------------------------------------------------------------- /R/isochrones.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice Isochrones 2 | #' 3 | #' Obtain areas of reachability from given locations. 4 | #' 5 | #' The Isochrone Service supports time and distance analyses for one single or 6 | #' multiple locations. You may also specify the isochrone interval or provide 7 | #' multiple exact isochrone range values. 8 | #' 9 | #' @template param-coordinates 10 | #' @templateVar argname locations 11 | #' @template param-profile 12 | #' @param range Maximum range value of the analysis in seconds for time and 13 | #' meters for distance. Alternatively a comma separated list of specific 14 | #' single range values. 15 | #' @template param-common 16 | #' @templateVar dotsargs parameters 17 | #' @templateVar endpoint isochrones 18 | #' @template return 19 | #' @templateVar return A GeoJSON object containing a FeatureCollection of Polygons 20 | #' corresponding to the accessible area, 21 | #' @template return-text 22 | #' @template return-parsed 23 | #' @template return-sf 24 | #' @examples 25 | #' # These examples might require interaction to query the local keyring, or 26 | #' # might fail due to network issues, so they are not run by default 27 | #' \dontrun{ 28 | #' ors_isochrones(c(8.34234, 48.23424), interval=20) 29 | #' 30 | #' locations <- list(c(8.681495, 49.41461), c(8.686507,49.41943)) 31 | #' ors_isochrones(locations, range=c(300, 200)) 32 | #' } 33 | #' @template author 34 | #' @export 35 | ors_isochrones <- function(locations, 36 | profile = ors_profile(), 37 | range = 60, 38 | ..., 39 | api_key = ors_api_key(), 40 | output = c("parsed", "text", "sf")) { 41 | 42 | ## required arguments with no default value 43 | if (missing(locations)) 44 | stop('Missing argument "locations"') 45 | 46 | ## required arguments with defaults 47 | profile <- match.arg(profile) 48 | output <- match.arg(output) 49 | 50 | ## wrap single point coordinate pairs into list 51 | if (is.vector(locations) && is.atomic(locations)) 52 | locations <- list(locations) 53 | 54 | names(locations) <- NULL 55 | 56 | ## request parameters 57 | body <- protect(list(locations = locations, range = range, ...), 58 | arrays = c("attributes", "range")) 59 | 60 | api_call( 61 | path = c("v2/isochrones", profile), 62 | api_key = api_key, 63 | body = body, 64 | encode = "json", 65 | response_format = "geojson", 66 | output = output, 67 | simplifyMatrix = FALSE 68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /R/leaflet.R: -------------------------------------------------------------------------------- 1 | #' Set Bounds of a Map Widget 2 | #' 3 | #' Helper function to set the bounds of a leaflet map widget. 4 | #' 5 | #' @inherit leaflet::fitBounds params return 6 | #' @param bbox A vector `c(lng1, lat1, lng2, lat2)` specifying the bounding box 7 | #' coordinates 8 | #' @importFrom leaflet fitBounds 9 | #' @template author 10 | #' @export 11 | fitBBox <- function(map, bbox) { 12 | if (is.null(bbox)) 13 | return(map) 14 | do.call(fitBounds, c(list(map), bbox)) 15 | } 16 | -------------------------------------------------------------------------------- /R/matrix.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice Matrix 2 | #' 3 | #' Obtain one-to-many, many-to-one and many-to-many matrices for time and 4 | #' distance. 5 | #' 6 | #' @template param-coordinates 7 | #' @templateVar argname locations 8 | #' @template param-profile 9 | #' @template param-common 10 | #' @templateVar dotsargs parameters 11 | #' @templateVar endpoint matrix 12 | #' @template return 13 | #' @templateVar return Duration or distance matrix for multiple source and destination 14 | #' points 15 | #' @template return-text 16 | #' @template return-parsed 17 | #' @examples 18 | #' # These examples might require interaction to query the local keyring, or 19 | #' # might fail due to network issues, so they are not run by default 20 | #' \dontrun{ 21 | #' coordinates <- list( 22 | #' c(9.970093, 48.477473), 23 | #' c(9.207916, 49.153868), 24 | #' c(37.573242, 55.801281), 25 | #' c(115.663757,38.106467) 26 | #' ) 27 | #' 28 | #' # query for duration and distance in km 29 | #' res <- ors_matrix(coordinates, metrics = c("duration", "distance"), units = "km") 30 | #' 31 | #' # duration in hours 32 | #' res$durations / 3600 33 | #' 34 | #' # distance in km 35 | #' res$distances 36 | #' } 37 | #' @template author 38 | #' @export 39 | ors_matrix <- function(locations, 40 | profile = ors_profile(), 41 | ..., 42 | api_key = ors_api_key(), 43 | output = c("parsed", "text")) { 44 | 45 | ## required arguments with no default value 46 | if (missing(locations)) 47 | stop('Missing argument "locations"') 48 | 49 | ## required arguments with defaults 50 | profile <- match.arg(profile) 51 | output <- match.arg(output) 52 | 53 | names(locations) <- NULL 54 | 55 | ## request parameters 56 | body <- protect(list(locations = locations, ...), 57 | arrays = c("destinations", "metrics", "sources")) 58 | 59 | api_call( 60 | path = c("v2/matrix", profile), 61 | api_key = api_key, 62 | body = body, 63 | encode = "json", 64 | output = output 65 | ) 66 | } 67 | -------------------------------------------------------------------------------- /R/optimization.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice Optimization 2 | #' 3 | #' Optimize a fleet of vehicles on a number of jobs. For more information, see 4 | #' the 5 | #' \href{https://github.com/VROOM-Project/vroom/blob/master/docs/API.md}{Vroom 6 | #' project API documentation}. 7 | #' @param jobs `data.frame` describing the places to visit 8 | #' @param vehicles `data.frame` describing the available vehicles 9 | #' @param matrix Optional two-dimensional array describing a custom travel-time 10 | #' matrix 11 | #' @template param-common 12 | #' @templateVar dotsargs parameters 13 | #' @templateVar endpoint optimization 14 | #' @template return 15 | #' @templateVar return Solution computed by the optimization endpoint formatted as described \href{https://github.com/VROOM-Project/vroom/blob/master/docs/API.md#output}{here} and 16 | #' @template return-text 17 | #' @template return-parsed 18 | #' @examples 19 | #' # These examples might require interaction to query the local keyring, or 20 | #' # might fail due to network issues, so they are not run by default 21 | #' \dontrun{ 22 | #' home_base <- c(2.35044, 48.71764) 23 | #' 24 | #' vehicles <- vehicles( 25 | #' id = 1:2, 26 | #' profile = "driving-car", 27 | #' start = home_base, 28 | #' end = home_base, 29 | #' capacity = 4, 30 | #' skills = list(c(1, 14), c(2, 14)), 31 | #' time_window = c(28800, 43200) 32 | #' ) 33 | #' 34 | #' locations <- list( 35 | #' c(1.98935, 48.701), 36 | #' c(2.03655, 48.61128), 37 | #' c(2.39719, 49.07611), 38 | #' c(2.41808, 49.22619), 39 | #' c(2.28325, 48.5958), 40 | #' c(2.89357, 48.90736) 41 | #' ) 42 | #' 43 | #' jobs <- jobs( 44 | #' id = 1:6, 45 | #' service = 300, 46 | #' amount = 1, 47 | #' location = locations, 48 | #' skills = list(1, 1, 2, 2, 14, 14) 49 | #' ) 50 | #' 51 | #' try( ors_optimization(jobs, vehicles) ) 52 | #' } 53 | #' @template author 54 | #' @export 55 | ors_optimization <- function(jobs, 56 | vehicles, 57 | matrix = NULL, 58 | ..., 59 | api_key = ors_api_key(), 60 | output = c("parsed", "text")) { 61 | ## required arguments with no default value 62 | if (missing(jobs)) 63 | stop('Missing required argument "jobs"') 64 | if (missing(vehicles)) 65 | stop('Missing required argument "vehicles"') 66 | 67 | ## required arguments with defaults 68 | output <- match.arg(output) 69 | 70 | if (!is.null(matrix)) 71 | matrix <- apply(matrix, c(1,2), as.integer) 72 | 73 | ## request parameters 74 | body <- protect( 75 | list(jobs = as_list(jobs), vehicles = as_list(vehicles), matrix = matrix, ...), 76 | arrays = c( 77 | "location", 78 | "amount", 79 | "skills", 80 | "time_windows", 81 | "start", 82 | "end", 83 | "capacity", 84 | "time_window" 85 | ) 86 | ) 87 | 88 | api_call( 89 | path = "optimization", 90 | api_key = api_key, 91 | body = body, 92 | encode = "json", 93 | output = output 94 | ) 95 | } 96 | 97 | #' @rdname ors_optimization 98 | #' @description The helper functions `jobs()` and `vehicles()` create 99 | #' data.frames which can be used as arguments to `ors_optimization()`. 100 | #' @param id An integer used as unique identifier 101 | #' @param location Coordinates array 102 | #' @param location_index Index of relevant row and column in custom matrix 103 | #' @param service Job service duration (defaults to 0) 104 | #' @param amount An array of integers describing multidimensional quantities 105 | #' @param skills An array of integers defining skills 106 | #' @param priority An integer in the \[0, 10\] range describing priority level 107 | #' (defaults to 0) 108 | #' @param time_windows An array of time_window objects describing valid slots 109 | #' for job service start 110 | #' @export 111 | jobs <- function(id, location, location_index, service, amount, skills, priority, time_windows) { 112 | n <- length(id) 113 | args <- list( 114 | id = id, 115 | location = if (!missing(location)) expand(location, n, TRUE), 116 | location_index = if (!missing(location_index)) expand(location_index, n, FALSE), 117 | service = if (!missing(service)) expand(service, n, FALSE), 118 | amount = if (!missing(amount)) expand(amount, n, TRUE), 119 | skills = if (!missing(skills)) expand(skills, n, TRUE), 120 | priority = if (!missing(priority)) expand(priority, n, FALSE), 121 | time_windows = if (!missing(time_windows)) expand(time_windows, n, TRUE) 122 | ) 123 | construct_df(args) 124 | } 125 | 126 | #' @rdname ors_optimization 127 | #' @param profile routing profile (defaults to car) 128 | #' @param start coordinates array 129 | #' @param start_index index of relevant row and column in custom matrix 130 | #' @param end coordinates array 131 | #' @param end_index index of relevant row and column in custom matrix 132 | #' @param capacity an array of integers describing multidimensional quantities 133 | #' @param time_window a time_window object describing working hours 134 | #' @export 135 | vehicles <- function(id, profile, start, start_index, end, end_index, capacity, skills, time_window) { 136 | n <- length(id) 137 | args <- list( 138 | id = id, 139 | profile = if (!missing(profile)) expand(profile, n, FALSE), 140 | start = if (!missing(start)) expand(start, n, TRUE), 141 | start_index = if (!missing(start_index)) expand(start_index, n, FALSE), 142 | end = if (!missing(end)) expand(end, n, TRUE), 143 | end_index = if (!missing(end_index)) expand(end_index, n, FALSE), 144 | capacity = if (!missing(capacity)) expand(capacity, n, TRUE), 145 | skills = if (!missing(skills)) expand(skills, n, TRUE), 146 | time_window = if (!missing(time_window)) expand(time_window, n, TRUE) 147 | ) 148 | construct_df(args) 149 | } 150 | -------------------------------------------------------------------------------- /R/pois.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice POIs 2 | #' 3 | #' Search for points of interest around points or in geometries. 4 | #' 5 | #' There are three different request types: `pois`, `stats` and `list`. 6 | #' 7 | #' `pois` returns a GeoJSON FeatureCollection in the bounding box specified in 8 | #' `geometry$bbox` or a GeoJSON geometry provided in `geometry$geojson`. `stats` 9 | #' does the same but groups by categories, ultimately returning a JSON object 10 | #' with the absolute numbers of POIs of a certain group. 11 | #' 12 | #' `list` returns a list of category groups and their ids. 13 | #' @param request One of the following: `"pois"`, `"stats"` or `"list"` 14 | #' @param geometry named list containing either a `geojson` geometry object 15 | #' (GeoJSON Point, LineString or Polygon) or a `bbox`, optionally buffered by 16 | #' a value provided `buffer` 17 | #' @template param-common 18 | #' @templateVar dotsargs request attributes 19 | #' @templateVar endpoint pois 20 | #' @template return 21 | #' @templateVar return A list of points of interest in the area specified in `geometry` 22 | #' @template return-text 23 | #' @template return-parsed 24 | #' @template return-sf 25 | #' @templateVar valid_for `request = "pois"` 26 | #' @examples 27 | #' # These examples might require interaction to query the local keyring, or 28 | #' # might fail due to network issues, so they are not run by default 29 | #' \dontrun{ 30 | #' # POI categories list 31 | #' ors_pois('list') 32 | #' 33 | #' # POIs around a buffered point 34 | #' geometry <- list(geojson = list(type = "Point", 35 | #' coordinates = c(8.8034, 53.0756)), 36 | #' buffer = 100) 37 | #' ors_pois(geometry = geometry) 38 | #' 39 | #' # alternative specification via bounding box 40 | #' ors_pois(geometry = list(bbox = list(c(8.8034, 53.0756), c(8.8034, 53.0756)), 41 | #' buffer = 100)) 42 | #' 43 | #' # POIs of given categories 44 | #' ors_pois(geometry = geometry, 45 | #' limit = 200, 46 | #' sortby = "distance", 47 | #' filters = list( 48 | #' category_ids = c(180, 245) 49 | #' )) 50 | #' 51 | #' # POIs of given category groups 52 | #' ors_pois(geometry = geometry, 53 | #' limit = 200, 54 | #' sortby = "distance", 55 | #' filters = list( 56 | #' category_group_ids = 160 57 | #' )) 58 | #' 59 | #' # POI Statistics 60 | #' ors_pois("stats", geometry = geometry) 61 | #' } 62 | #' @template author 63 | #' @export 64 | ors_pois <- function(request = c('pois', 'stats', 'list'), 65 | geometry, 66 | ..., 67 | api_key = ors_api_key(), 68 | output = c("parsed", "text", "sf")) { 69 | request <- match.arg(request) 70 | output <- match.arg(output) 71 | 72 | if (request!="pois" && output=="sf") 73 | stop('"sf" output available only for request type "pois"') 74 | 75 | dots <- list(...) 76 | 77 | if (!is.null(dots[["filters"]])) 78 | dots[["filters"]] <- protect(dots[["filters"]]) 79 | 80 | body <- c(request = request, dots) 81 | 82 | if (request!="list") { 83 | if (missing(geometry)) 84 | stop('Missing argument "geometry"') 85 | else 86 | body$geometry <- geometry 87 | } 88 | 89 | api_call( 90 | "pois", 91 | api_key = api_key, 92 | body = body, 93 | encode = "json", 94 | output = output 95 | ) 96 | } 97 | -------------------------------------------------------------------------------- /R/profiles.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice Profiles 2 | #' 3 | #' List of available modes of transport. 4 | #' 5 | #' Convenience function for specifying the profile in [ors_directions()], 6 | #' [ors_isochrones()] and [ors_matrix()]. 7 | #' 8 | #' @param mode Profile label. 9 | #' @return Profile name, or named vector of available profiles. 10 | #' @examples 11 | #' # list availbale profiles 12 | #' ors_profile() 13 | #' 14 | #' # retrieve full profile name based on label 15 | #' ors_profile("car") 16 | #' @seealso [ors_directions()], [ors_isochrones()], [ors_matrix()] 17 | #' @template author 18 | #' @export 19 | ors_profile <- function(mode = c("car", "hgv", "bike", "roadbike", "mtb", "e-bike", "walking", "hiking", "wheelchair")) { 20 | profiles <- c( 21 | `car` = 'driving-car', 22 | `hgv` = 'driving-hgv', 23 | `bike` = 'cycling-regular', 24 | `roadbike` = 'cycling-road', 25 | `mtb` = 'cycling-mountain', 26 | `e-bike` = 'cycling-electric', 27 | `walking` = 'foot-walking', 28 | `hiking`= 'foot-hiking', 29 | `wheelchair` = 'wheelchair' 30 | ) 31 | 32 | if (missing(mode)) 33 | profiles 34 | else 35 | profiles[[match.arg(mode)]] 36 | } 37 | -------------------------------------------------------------------------------- /R/snap.R: -------------------------------------------------------------------------------- 1 | #' Openrouteservice Snapping 2 | #' 3 | #' Snap coordinates to road network 4 | #' 5 | #' @template param-coordinates 6 | #' @templateVar argname locations 7 | #' @template param-profile 8 | #' @param radius Maximum radius in meters around given coordinates to search for graph edges 9 | #' @param format Response format, defaults to `"geojson"` 10 | #' @template param-common 11 | #' @templateVar dotsargs parameters 12 | #' @templateVar endpoint snap 13 | #' @template return 14 | #' @templateVar return Coordinates of snapped location(s) and distance to the original point(s) 15 | #' @template return-text 16 | #' @template return-parsed 17 | #' @template return-sf 18 | #' @examples 19 | #' # These examples might require interaction to query the local keyring, or 20 | #' # might fail due to network issues, so they are not run by default 21 | #' \dontrun{ 22 | #' locations <- list( 23 | #' c(8.669629, 49.413025), 24 | #' c(8.675841, 49.418532), 25 | #' c(8.665144, 49.415594) 26 | #' ) 27 | #' 28 | #' # query for locations snapped onto the OpenStreetMap road network 29 | #' res <- ors_snap(locations, radius = 350) 30 | #' } 31 | #' @template author 32 | #' @export 33 | ors_snap <- function(locations, 34 | profile = ors_profile(), 35 | radius, 36 | format = c('geojson', 'json'), 37 | ..., 38 | api_key = ors_api_key(), 39 | output = c("parsed", "text", "sf")) { 40 | ## required arguments with no default value 41 | if (missing(locations)) 42 | stop('Missing argument "locations"') 43 | if (missing(radius)) 44 | stop('Missing argument "radius"') 45 | 46 | ## required arguments with defaults 47 | profile <- match.arg(profile) 48 | format <- match.arg(format) 49 | output <- match.arg(output) 50 | 51 | names(locations) <- NULL 52 | 53 | ## request parameters 54 | body <- list(locations = locations, radius = radius, ...) 55 | 56 | api_call( 57 | path = c("v2/snap", profile, format), 58 | api_key = api_key, 59 | body = body, 60 | encode = "json", 61 | output = output 62 | )} 63 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | # protect vectors of length 1 from unboxing when converting to JSON 2 | protect <- function(args, arrays) { 3 | names <- names(args) 4 | if (missing(arrays)) 5 | arrays <- names 6 | 7 | array_args <- 8 | if (is.null(names)) 9 | rep_len(FALSE, length(args)) 10 | else 11 | names %in% arrays 12 | 13 | if (any(array_args)) { 14 | args[array_args] <- lapply(args[array_args], I) 15 | arrays <- arrays[!(arrays %in% names)] 16 | } 17 | 18 | # call recursively 19 | lists <- !array_args & vapply(args, is.list, logical(1L), USE.NAMES = FALSE) 20 | 21 | if (any(lists) && length(arrays)>0L) 22 | args[lists] <- lapply(args[lists], protect, arrays) 23 | 24 | args 25 | } 26 | 27 | # convert a data frame to list-based representation to be serialized to JSON 28 | as_list <- function(x) { 29 | if (is.data.frame(x)) { 30 | # go from data frame to nested list 31 | json <- toJSON(x, auto_unbox = FALSE, digits = 16) 32 | list <- fromJSON(json, simplifyDataFrame = FALSE) 33 | # remove any missing values 34 | x <- lapply(list, compact) 35 | } 36 | x 37 | } 38 | 39 | construct_df <- function(args) { 40 | args <- compact(args) 41 | structure( 42 | args, 43 | names = names(args), 44 | class = "data.frame", 45 | row.names = 1:length(args[[1]]) 46 | ) 47 | } 48 | 49 | expand <- function(x, n, is_vector) { 50 | if (is_vector) { 51 | if (!is.list(x)) 52 | x <- list(x) 53 | else if (is.data.frame(x)) { 54 | x <- as.matrix(x) 55 | x <- lapply(1:nrow(x), function(i) unname(x[i,])) 56 | } 57 | } 58 | rep_len(x, n) 59 | } 60 | 61 | compact <- function (x) { 62 | empty <- vapply(x, is_empty, logical(1L)) 63 | x[!empty] 64 | } 65 | 66 | is_empty <- function(x) { 67 | length(x) == 0 68 | } 69 | 70 | on_cran <- function() { 71 | !interactive() && !isTRUE(as.logical(Sys.getenv("NOT_CRAN", "false"))) 72 | } 73 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onLoad <- function(lib, pkg) { 2 | validator$instance <- jsonvalidate::json_validator(system.file("schema/geojson.json", package = pkg)) 3 | } 4 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: rmarkdown::md_document 3 | --- 4 | 5 | 6 | 7 | 8 | [![R-CMD-check](https://github.com/GIScience/openrouteservice-r/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/GIScience/openrouteservice-r/actions/workflows/R-CMD-check.yaml) 9 | [![Coverage Status](https://img.shields.io/codecov/c/github/GIScience/openrouteservice-r/master.svg)](https://app.codecov.io/github/GIScience/openrouteservice-r?branch=master) 10 | [![lifecycle](https://lifecycle.r-lib.org/articles/figures/lifecycle-stable.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) 11 | [![CRAN checks](https://badges.cranchecks.info/summary/openrouteservice.svg)](https://cran.r-project.org/web/checks/check_results_openrouteservice.html) 12 | [![CRAN release](https://www.r-pkg.org/badges/version-ago/openrouteservice)](https://cran.r-project.org/package=openrouteservice) 13 | [![CRAN downloads](https://cranlogs.r-pkg.org:443/badges/openrouteservice)](https://cran.r-project.org/package=openrouteservice) 14 | 15 | 16 | # openrouteservice R client 17 | 18 | ```{r readme, echo = FALSE, results = 'asis'} 19 | lines = readLines("vignettes/openrouteservice.Rmd") 20 | ids = grep("", lines) + c(1, -1) 21 | readme = lines[do.call(":", as.list(ids))] 22 | readme = gsub("^#(#+)(.*)", "\\1\\2", readme) 23 | cat(knitr::knit_child(text=readme, quiet=TRUE)) 24 | ``` 25 | 26 | ## Get started 27 | 28 | See the package 29 | [vignette](https://giscience.github.io/openrouteservice-r/articles/openrouteservice.html) 30 | for an overview of the offered functionality. 31 | 32 | ## Local ORS instance 33 | 34 | The default is to fire any requests against the free public services at 35 | . In order to query a different openrouteservice 36 | instance, say a local one, set 37 | 38 | ```{r openrouteservice.url, eval=FALSE} 39 | options(openrouteservice.url = "http://localhost:8082/ors") 40 | ``` 41 | 42 | If necessary, endpoint configuration can be further customized through 43 | `openrouteservice.paths` which specifies a named list of paths. The defaults are 44 | equivalent of having 45 | 46 | ```{r openrouteservice.paths, echo=FALSE, comment=NA} 47 | opts_str <- "options(openrouteservice.paths = %s)" 48 | nch <- nchar(opts_str) + 1L 49 | ors_paths <- unlist(strsplit(deparse(openrouteservice:::ors_path(), 500L), ",")) 50 | indent <- paste0(rep(" ", nch), collapse="") 51 | cat(sprintf(opts_str, paste0(ors_paths, collapse = paste(",", indent, sep="\n")))) 52 | options(openrouteservice.path = list(directions = "v2/directions")) 53 | ``` 54 | 55 | ## Package news 56 | 57 | ```{r news, echo = FALSE, results = 'asis'} 58 | lines = readLines("NEWS.md") 59 | lines = gsub("^# openrouteservice (.*)", "# version \\1", lines) 60 | versions = grep("^# ", lines) 61 | ## select only n latest news 62 | n = 4 63 | from = 1 64 | to = if (length(versions) > n) versions[n+1]-1 else length(lines) 65 | news = lines[from:to] 66 | news = gsub("^(#+)(.*)", "##\\1\\2", news) 67 | cat(paste(news, collapse = "\n")) 68 | ``` 69 | 70 | ## Publications using openrouteservice R package 71 | 72 | Please feel free to reach out if you would like to have your work added to the list below. 73 | 74 | ```{r references, echo = FALSE, results = 'asis'} 75 | lines = readLines("references.md") 76 | lines = gsub('^', '', lines) 77 | lines = gsub('^', '', lines) 78 | lines = gsub(' $', '', lines) 79 | cat(paste(lines, collapse = "\n")) 80 | ``` 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | [![R-CMD-check](https://github.com/GIScience/openrouteservice-r/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/GIScience/openrouteservice-r/actions/workflows/R-CMD-check.yaml) 5 | [![Coverage 6 | Status](https://img.shields.io/codecov/c/github/GIScience/openrouteservice-r/master.svg)](https://app.codecov.io/github/GIScience/openrouteservice-r?branch=master) 7 | [![lifecycle](https://lifecycle.r-lib.org/articles/figures/lifecycle-stable.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) 8 | [![CRAN 9 | checks](https://badges.cranchecks.info/summary/openrouteservice.svg)](https://cran.r-project.org/web/checks/check_results_openrouteservice.html) 10 | [![CRAN 11 | release](https://www.r-pkg.org/badges/version-ago/openrouteservice)](https://cran.r-project.org/package=openrouteservice) 12 | [![CRAN 13 | downloads](https://cranlogs.r-pkg.org:443/badges/openrouteservice)](https://cran.r-project.org/package=openrouteservice) 14 | 15 | 16 | # openrouteservice R client 17 | 18 | *openrouteservice* R package provides easy access to the 19 | [openrouteservice](https://openrouteservice.org) (ORS) API from R. It 20 | allows you to painlessly consume the following services: 21 | 22 | - [directions](https://openrouteservice.org/dev/#/api-docs/v2/directions/%7Bprofile%7D/post) 23 | (routing) 24 | - [geocoding](https://openrouteservice.org/dev/#/api-docs/geocode) 25 | powered by [Pelias](https://pelias.io) 26 | - [isochrones](https://openrouteservice.org/dev/#/api-docs/v2/isochrones/%7Bprofile%7D/post) 27 | (accessibility) 28 | - time-distance 29 | [matrices](https://openrouteservice.org/dev/#/api-docs/v2/matrix/%7Bprofile%7D/post) 30 | - [snapping](https://openrouteservice.org/dev/#/api-docs/v2/snap/%7Bprofile%7D/post) 31 | to OpenStreetMap ways 32 | - [exporting](https://openrouteservice.org/dev/#/api-docs/v2/export/%7Bprofile%7D/post) 33 | the underlying routing graph structure 34 | - [pois](https://openrouteservice.org/dev/#/api-docs/pois/post) 35 | (points of interest) 36 | - SRTM 37 | [elevation](https://openrouteservice.org/dev/#/api-docs/elevation) 38 | for point and lines geometries 39 | - routing 40 | [optimization](https://openrouteservice.org/dev/#/api-docs/optimization/post) 41 | based on [Vroom](http://vroom-project.org/) 42 | 43 | ## Disclaimer 44 | 45 | By using this package, you agree to the ORS [terms and 46 | conditions](https://openrouteservice.org/terms-of-service/). 47 | 48 | ## Installation 49 | 50 | The latest release version can be readily obtained from CRAN via a call 51 | to 52 | 53 | install.packages("openrouteservice") 54 | 55 | For running the current development version from GitHub it is 56 | recommended to use [pak](https://CRAN.R-project.org/package=pak), as it 57 | handles the installation of all the necessary packages and their system 58 | dependencies automatically. 59 | 60 | # install.packages("pak") 61 | pak::pak("GIScience/openrouteservice-r") 62 | 63 | ## Get started 64 | 65 | See the package 66 | [vignette](https://giscience.github.io/openrouteservice-r/articles/openrouteservice.html) 67 | for an overview of the offered functionality. 68 | 69 | ## Local ORS instance 70 | 71 | The default is to fire any requests against the free public services at 72 | <api.openrouteservice.org>. In order to query a different 73 | openrouteservice instance, say a local one, set 74 | 75 | options(openrouteservice.url = "http://localhost:8082/ors") 76 | 77 | If necessary, endpoint configuration can be further customized through 78 | `openrouteservice.paths` which specifies a named list of paths. The 79 | defaults are equivalent of having 80 | 81 | options(openrouteservice.paths = list(directions = "v2/directions", 82 | isochrones = "v2/isochrones", 83 | matrix = "v2/matrix", 84 | geocode = "geocode", 85 | pois = "pois", 86 | elevation = "elevation", 87 | optimization = "optimization", 88 | snap = "v2/snap", 89 | export = "v2/export")) 90 | 91 | ## Package news 92 | 93 | ### version 0.6.0 94 | 95 | #### NEW FEATURES 96 | 97 | - Enable export endpoint. 98 | 99 | ### version 0.5.2 100 | 101 | #### NEW FEATURES 102 | 103 | - sf output for snapping. 104 | 105 | ### version 0.5.1 106 | 107 | #### BUG FIXES 108 | 109 | - sf output for POIs endpoint (#81) 110 | 111 | ### version 0.5.0 112 | 113 | #### NEW FEATURES 114 | 115 | - Enable snap endpoint. 116 | 117 | ## Publications using openrouteservice R package 118 | 119 | Please feel free to reach out if you would like to have your work added 120 | to the list below. 121 | 122 | 1. Baumer BS, Kaplan DT, Horton NJ. Modern data science with r. 123 | Chapman; Hall/CRC; 2017. 124 | 125 | 2. Cervigni E, Renton M, McKenzie FH, Hickling S, Olaru D. Describing 126 | and mapping diversity and accessibility of the urban food 127 | environment with open data and tools. Applied Geography. 128 | 2020;125:102352. 129 | 130 | 3. Petricola S, Reinmuth M, Lautenbach S, Hatfield C, Zipf A. Assessing 131 | road criticality and loss of healthcare accessibility during floods: 132 | The case of cyclone idai, mozambique 2019. International journal of 133 | health geographics. 2022;21(1):14. 134 | 135 | 4. Weenink P. Overcoming the modifiable areal unit problem (MAUP) of 136 | socio-economic variables in real estate modelling 137 | *P**h**D**t**h**e**s**i**s* 138 | . 2022. 139 | 140 | 5. Shields N, Willis C, Imms C, McKenzie G, Van Dorsselaer B, Bruder 141 | AM, et al. Feasibility of scaling-up a community-based exercise 142 | program for young people with disability. Disability and 143 | Rehabilitation. 2022;44(9):1669–81. 144 | 145 | 6. Veloso R, Cespedes J, Caunhye A, Alem D. Brazilian disaster datasets 146 | and real-world instances for optimization and machine learning. Data 147 | in brief. 2022;42:108012. 148 | 149 | 7. Cubells J, Miralles-Guasch C, Marquet O. E-scooter and bike-share 150 | route choice and detours: Modelling the influence of built 151 | environment and sociodemographic factors. Journal of transport 152 | geography. 2023;111:103664. 153 | 154 | 8. Bhowon Y, Prendergast LA, Taylor NF, Shields N. Using geospatial 155 | analysis to determine the proximity of community gyms for a 156 | population-based cohort of young people with cerebral palsy. 157 | Physiotherapy Canada. 2023;e20220064. 158 | 159 | 9. Amato S, Benson JS, Stewart B, Sarathy A, Osler T, Hosmer D, et 160 | al. Current patterns of trauma center proliferation have not led to 161 | proportionate improvements in access to care or mortality after 162 | injury: An ecologic study. Journal of Trauma and Acute Care Surgery. 163 | 2023;94(6):755–64. 164 | 165 | 10. Jain A, LaValley M, Dukes K, Lane K, Winter M, Spangler KR, et 166 | al. Modeling health and well-being measures using ZIP code spatial 167 | neighborhood patterns. Scientific Reports. 2024;14(1):9180. 168 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | api 2 | AppVeyor 3 | FeatureCollection 4 | geocode 5 | geocoding 6 | Geocoding 7 | geoJSON 8 | GeoJSON 9 | GPX 10 | isochrone 11 | Isochrone 12 | isochrones 13 | Isochrones 14 | JSON 15 | keyring 16 | keyrings 17 | lifecycle 18 | LineString 19 | ORS 20 | Pelias 21 | pois 22 | POIs 23 | reachability 24 | Reachability 25 | SRTM 26 | str 27 | ggforce 28 | ggplot 29 | mapview 30 | natively 31 | polyline 32 | postprocessing 33 | VROOM 34 | Vroom 35 | VRP 36 | -------------------------------------------------------------------------------- /inst/schema/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2014 Mads Kristensen 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 4 | 5 | http://www.apache.org/licenses/LICENSE-2.0 6 | 7 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 8 | -------------------------------------------------------------------------------- /inst/schema/README.md: -------------------------------------------------------------------------------- 1 | The geojson schema here is taken from the [SchemaStore](https://github.com/SchemaStore/schemastore) repository. It is distributed under the Apache 2.0 license (see LICENSE.md) 2 | -------------------------------------------------------------------------------- /inst/schema/geojson.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "additionalProperties": true, 4 | "definitions": { 5 | "coordinates": { 6 | "title": "Coordinates", 7 | "type": "array", 8 | "items": { 9 | "oneOf": [ 10 | { 11 | "type": "array" 12 | }, 13 | { 14 | "type": "number" 15 | } 16 | ] 17 | } 18 | }, 19 | "geometry": { 20 | "title": "Geometry", 21 | "description": "A geometry is a GeoJSON object where the type member's value is one of the following strings: `Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`, or `GeometryCollection`.", 22 | "properties": { 23 | "type": { 24 | "enum": [ 25 | "Point", 26 | "MultiPoint", 27 | "LineString", 28 | "MultiLineString", 29 | "Polygon", 30 | "MultiPolygon", 31 | "GeometryCollection" 32 | ] 33 | } 34 | } 35 | }, 36 | "feature": { 37 | "title": "Feature", 38 | "description": "A GeoJSON object with the type `Feature` is a feature object.\n\n* A feature object must have a member with the name `geometry`. The value of the geometry member is a geometry object as defined above or a JSON null value.\n\n* A feature object must have a member with the name `properties`. The value of the properties member is an object (any JSON object or a JSON null value).\n\n* If a feature has a commonly used identifier, that identifier should be included as a member of the feature object with the name `id`.", 39 | "required": ["geometry", "properties"], 40 | "properties": { 41 | "type": { 42 | "enum": ["Feature"] 43 | }, 44 | "geometry": { 45 | "title": "Geometry", 46 | "oneOf": [ 47 | { 48 | "$ref": "#/definitions/geometry" 49 | }, 50 | { 51 | "type": "null" 52 | } 53 | ] 54 | }, 55 | "properties": { 56 | "title": "Properties", 57 | "oneOf": [ 58 | { 59 | "type": "object" 60 | }, 61 | { 62 | "type": "null" 63 | } 64 | ] 65 | }, 66 | "id": {} 67 | } 68 | }, 69 | "linearRingCoordinates": { 70 | "title": "Linear Ring Coordinates", 71 | "description": "A LinearRing is closed LineString with 4 or more positions. The first and last positions are equivalent (they represent equivalent points). Though a LinearRing is not explicitly represented as a GeoJSON geometry type, it is referred to in the Polygon geometry type definition.", 72 | "allOf": [ 73 | { 74 | "$ref": "#/definitions/lineStringCoordinates" 75 | }, 76 | { 77 | "minItems": 4 78 | } 79 | ] 80 | }, 81 | "lineStringCoordinates": { 82 | "title": "Line String Coordinates", 83 | "description": "For type `LineString`, the `coordinates` member must be an array of two or more positions.", 84 | "allOf": [ 85 | { 86 | "$ref": "#/definitions/coordinates" 87 | }, 88 | { 89 | "minLength": 2, 90 | "items": { 91 | "$ref": "#/definitions/position" 92 | } 93 | } 94 | ] 95 | }, 96 | "polygonCoordinates": { 97 | "title": "Polygon Coordinates", 98 | "description": "For type `Polygon`, the `coordinates` member must be an array of LinearRing coordinate arrays. For Polygons with multiple rings, the first must be the exterior ring and any others must be interior rings or holes.", 99 | "allOf": [ 100 | { 101 | "$ref": "#/definitions/coordinates" 102 | }, 103 | { 104 | "items": { 105 | "$ref": "#/definitions/linearRingCoordinates" 106 | } 107 | } 108 | ] 109 | }, 110 | "position": { 111 | "title": "Position", 112 | "type": "array", 113 | "description": "A position is the fundamental geometry construct. The `coordinates` member of a geometry object is composed of one position (in the case of a Point geometry), an array of positions (LineString or MultiPoint geometries), an array of arrays of positions (Polygons, MultiLineStrings), or a multidimensional array of positions (MultiPolygon).\n\nA position is represented by an array of numbers. There must be at least two elements, and may be more. The order of elements must follow x, y, z order (easting, northing, altitude for coordinates in a projected coordinate reference system, or longitude, latitude, altitude for coordinates in a geographic coordinate reference system). Any number of additional elements are allowed -- interpretation and meaning of additional elements is beyond the scope of this specification.", 114 | "minItems": 2, 115 | "items": { 116 | "type": "number" 117 | } 118 | } 119 | }, 120 | "description": "This object represents a geometry, feature, or collection of features.", 121 | "id": "https://json.schemastore.org/geojson", 122 | "oneOf": [ 123 | { 124 | "title": "Point", 125 | "description": "For type `Point`, the `coordinates` member must be a single position.", 126 | "required": ["coordinates"], 127 | "properties": { 128 | "type": { 129 | "enum": ["Point"] 130 | }, 131 | "coordinates": { 132 | "allOf": [ 133 | { 134 | "$ref": "#/definitions/coordinates" 135 | }, 136 | { 137 | "$ref": "#/definitions/position" 138 | } 139 | ] 140 | } 141 | }, 142 | "allOf": [ 143 | { 144 | "$ref": "#/definitions/geometry" 145 | } 146 | ] 147 | }, 148 | { 149 | "title": "Multi Point Geometry", 150 | "description": "For type `MultiPoint`, the `coordinates` member must be an array of positions.", 151 | "required": ["coordinates"], 152 | "properties": { 153 | "type": { 154 | "enum": ["MultiPoint"] 155 | }, 156 | "coordinates": { 157 | "allOf": [ 158 | { 159 | "$ref": "#/definitions/coordinates" 160 | }, 161 | { 162 | "items": { 163 | "$ref": "#/definitions/position" 164 | } 165 | } 166 | ] 167 | } 168 | }, 169 | "allOf": [ 170 | { 171 | "$ref": "#/definitions/geometry" 172 | } 173 | ] 174 | }, 175 | { 176 | "title": "Line String", 177 | "description": "For type `LineString`, the `coordinates` member must be an array of two or more positions.\n\nA LinearRing is closed LineString with 4 or more positions. The first and last positions are equivalent (they represent equivalent points). Though a LinearRing is not explicitly represented as a GeoJSON geometry type, it is referred to in the Polygon geometry type definition.", 178 | "required": ["coordinates"], 179 | "properties": { 180 | "type": { 181 | "enum": ["LineString"] 182 | }, 183 | "coordinates": { 184 | "$ref": "#/definitions/lineStringCoordinates" 185 | } 186 | }, 187 | "allOf": [ 188 | { 189 | "$ref": "#/definitions/geometry" 190 | } 191 | ] 192 | }, 193 | { 194 | "title": "MultiLineString", 195 | "description": "For type `MultiLineString`, the `coordinates` member must be an array of LineString coordinate arrays.", 196 | "required": ["coordinates"], 197 | "properties": { 198 | "type": { 199 | "enum": ["MultiLineString"] 200 | }, 201 | "coordinates": { 202 | "allOf": [ 203 | { 204 | "$ref": "#/definitions/coordinates" 205 | }, 206 | { 207 | "items": { 208 | "$ref": "#/definitions/lineStringCoordinates" 209 | } 210 | } 211 | ] 212 | } 213 | }, 214 | "allOf": [ 215 | { 216 | "$ref": "#/definitions/geometry" 217 | } 218 | ] 219 | }, 220 | { 221 | "title": "Polygon", 222 | "description": "For type `Polygon`, the `coordinates` member must be an array of LinearRing coordinate arrays. For Polygons with multiple rings, the first must be the exterior ring and any others must be interior rings or holes.", 223 | "required": ["coordinates"], 224 | "properties": { 225 | "type": { 226 | "enum": ["Polygon"] 227 | }, 228 | "coordinates": { 229 | "$ref": "#/definitions/polygonCoordinates" 230 | } 231 | }, 232 | "allOf": [ 233 | { 234 | "$ref": "#/definitions/geometry" 235 | } 236 | ] 237 | }, 238 | { 239 | "title": "Multi-Polygon Geometry", 240 | "description": "For type `MultiPolygon`, the `coordinates` member must be an array of Polygon coordinate arrays.", 241 | "required": ["coordinates"], 242 | "properties": { 243 | "type": { 244 | "enum": ["MultiPolygon"] 245 | }, 246 | "coordinates": { 247 | "allOf": [ 248 | { 249 | "$ref": "#/definitions/coordinates" 250 | }, 251 | { 252 | "items": { 253 | "$ref": "#/definitions/polygonCoordinates" 254 | } 255 | } 256 | ] 257 | } 258 | }, 259 | "allOf": [ 260 | { 261 | "$ref": "#/definitions/geometry" 262 | } 263 | ] 264 | }, 265 | { 266 | "title": "Geometry Collection", 267 | "description": "A GeoJSON object with type `GeometryCollection` is a geometry object which represents a collection of geometry objects.\n\nA geometry collection must have a member with the name `geometries`. The value corresponding to `geometries` is an array. Each element in this array is a GeoJSON geometry object.", 268 | "required": ["geometries"], 269 | "properties": { 270 | "type": { 271 | "enum": ["GeometryCollection"] 272 | }, 273 | "geometries": { 274 | "title": "Geometries", 275 | "type": "array", 276 | "items": { 277 | "$ref": "#/definitions/geometry" 278 | } 279 | } 280 | }, 281 | "allOf": [ 282 | { 283 | "$ref": "#/definitions/geometry" 284 | } 285 | ] 286 | }, 287 | { 288 | "$ref": "#/definitions/feature" 289 | }, 290 | { 291 | "title": "Feature Collection", 292 | "description": "A GeoJSON object with the type `FeatureCollection` is a feature collection object.\n\nAn object of type `FeatureCollection` must have a member with the name `features`. The value corresponding to `features` is an array. Each element in the array is a feature object as defined above.", 293 | "required": ["features"], 294 | "properties": { 295 | "type": { 296 | "enum": ["FeatureCollection"] 297 | }, 298 | "features": { 299 | "title": "Features", 300 | "type": "array", 301 | "items": { 302 | "$ref": "#/definitions/feature" 303 | } 304 | } 305 | } 306 | } 307 | ], 308 | "properties": { 309 | "type": { 310 | "title": "Type", 311 | "type": "string", 312 | "description": "The type of GeoJSON object.", 313 | "enum": [ 314 | "Point", 315 | "MultiPoint", 316 | "LineString", 317 | "MultiLineString", 318 | "Polygon", 319 | "MultiPolygon", 320 | "GeometryCollection", 321 | "Feature", 322 | "FeatureCollection" 323 | ] 324 | }, 325 | "crs": { 326 | "title": "Coordinate Reference System (CRS)", 327 | "description": "The coordinate reference system (CRS) of a GeoJSON object is determined by its `crs` member (referred to as the CRS object below). If an object has no crs member, then its parent or grandparent object's crs member may be acquired. If no crs member can be so acquired, the default CRS shall apply to the GeoJSON object.\n\n* The default CRS is a geographic coordinate reference system, using the WGS84 datum, and with longitude and latitude units of decimal degrees.\n\n* The value of a member named `crs` must be a JSON object (referred to as the CRS object below) or JSON null. If the value of CRS is null, no CRS can be assumed.\n\n* The crs member should be on the top-level GeoJSON object in a hierarchy (in feature collection, feature, geometry order) and should not be repeated or overridden on children or grandchildren of the object.\n\n* A non-null CRS object has two mandatory members: `type` and `properties`.\n\n* The value of the type member must be a string, indicating the type of CRS object.\n\n* The value of the properties member must be an object.\n\n* CRS shall not change coordinate ordering.", 328 | "oneOf": [ 329 | { 330 | "type": "null" 331 | }, 332 | { 333 | "type": "object", 334 | "required": ["type", "properties"], 335 | "properties": { 336 | "type": { 337 | "title": "CRS Type", 338 | "type": "string", 339 | "description": "The value of the type member must be a string, indicating the type of CRS object.", 340 | "minLength": 1 341 | }, 342 | "properties": { 343 | "title": "CRS Properties", 344 | "type": "object" 345 | } 346 | } 347 | } 348 | ], 349 | "not": { 350 | "anyOf": [ 351 | { 352 | "properties": { 353 | "type": { 354 | "enum": ["name"] 355 | }, 356 | "properties": { 357 | "not": { 358 | "required": ["name"], 359 | "properties": { 360 | "name": { 361 | "type": "string", 362 | "minLength": 1 363 | } 364 | } 365 | } 366 | } 367 | } 368 | }, 369 | { 370 | "properties": { 371 | "type": { 372 | "enum": ["link"] 373 | }, 374 | "properties": { 375 | "not": { 376 | "title": "Link Object", 377 | "type": "object", 378 | "required": ["href"], 379 | "properties": { 380 | "href": { 381 | "title": "href", 382 | "type": "string", 383 | "description": "The value of the required `href` member must be a dereferenceable URI.", 384 | "format": "uri" 385 | }, 386 | "type": { 387 | "title": "Link Object Type", 388 | "type": "string", 389 | "description": "The value of the optional `type` member must be a string that hints at the format used to represent CRS parameters at the provided URI. Suggested values are: `proj4`, `ogcwkt`, `esriwkt`, but others can be used." 390 | } 391 | } 392 | } 393 | } 394 | } 395 | } 396 | ] 397 | } 398 | }, 399 | "bbox": { 400 | "title": "Bounding Box", 401 | "type": "array", 402 | "description": "To include information on the coordinate range for geometries, features, or feature collections, a GeoJSON object may have a member named `bbox`. The value of the bbox member must be a 2*n array where n is the number of dimensions represented in the contained geometries, with the lowest values for all axes followed by the highest values. The axes order of a bbox follows the axes order of geometries. In addition, the coordinate reference system for the bbox is assumed to match the coordinate reference system of the GeoJSON object of which it is a member.", 403 | "minItems": 4, 404 | "items": { 405 | "type": "number" 406 | } 407 | } 408 | }, 409 | "required": ["type"], 410 | "title": "GeoJSON Object", 411 | "type": "object" 412 | } 413 | -------------------------------------------------------------------------------- /man-roxygen/author.R: -------------------------------------------------------------------------------- 1 | #' @author Andrzej Oleś 2 | -------------------------------------------------------------------------------- /man-roxygen/param-common.R: -------------------------------------------------------------------------------- 1 | #' @param ... Optional <%= dotsargs %> as described \href{<%= doc_url(endpoint) %>}{here} 2 | #' @param api_key Character scalar containing openrouteservice API key 3 | #' @param output Output format. By default the response is being parsed to a list-based R object 4 | -------------------------------------------------------------------------------- /man-roxygen/param-coordinates.R: -------------------------------------------------------------------------------- 1 | #' @param <%= argname %> List of `longitude, latitude` coordinate pairs<%= if (exists("suffix")) paste0(" ", suffix)%>, alternatively a two column `matrix` or `data.frame`. 2 | -------------------------------------------------------------------------------- /man-roxygen/param-profile.R: -------------------------------------------------------------------------------- 1 | #' @param profile Route profile, defaults to \code{"driving-car"}. 2 | -------------------------------------------------------------------------------- /man-roxygen/return-parsed.R: -------------------------------------------------------------------------------- 1 | #' @return - for `"parsed"`, a parsed R object. 2 | -------------------------------------------------------------------------------- /man-roxygen/return-sf.R: -------------------------------------------------------------------------------- 1 | #' @return - for `"sf"`, a simple features \code{\link[sf]{sf}} object. <%= if (exists("valid_for")) paste0("Valid only for argument ", valid_for, ".") %> 2 | -------------------------------------------------------------------------------- /man-roxygen/return-text.R: -------------------------------------------------------------------------------- 1 | #' @return - for `"text"`, a character vector of length 1 re-encoded to UTF-8. 2 | -------------------------------------------------------------------------------- /man-roxygen/return.R: -------------------------------------------------------------------------------- 1 | #' @return <%= return %> structured according to `output`: 2 | -------------------------------------------------------------------------------- /man/fitBBox.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/leaflet.R 3 | \name{fitBBox} 4 | \alias{fitBBox} 5 | \title{Set Bounds of a Map Widget} 6 | \usage{ 7 | fitBBox(map, bbox) 8 | } 9 | \arguments{ 10 | \item{map}{a map widget object created from \code{\link[leaflet]{leaflet}()}} 11 | 12 | \item{bbox}{A vector \code{c(lng1, lat1, lng2, lat2)} specifying the bounding box 13 | coordinates} 14 | } 15 | \value{ 16 | The modified map widget. 17 | } 18 | \description{ 19 | Helper function to set the bounds of a leaflet map widget. 20 | } 21 | \author{ 22 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 23 | } 24 | -------------------------------------------------------------------------------- /man/ors_api_key.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/api_key.R 3 | \name{ors_api_key} 4 | \alias{ors_api_key} 5 | \title{API key management} 6 | \usage{ 7 | ors_api_key(key, service = "openrouteservice", username = NULL, keyring = NULL) 8 | } 9 | \arguments{ 10 | \item{key}{API key value provided as a character scalar} 11 | 12 | \item{service}{Service name, a character scalar.} 13 | 14 | \item{username}{Username, a character scalar, or \code{NULL} if the key 15 | is not associated with a username.} 16 | 17 | \item{keyring}{For systems that support multiple keyrings, specify 18 | the name of the keyring to use here. If \code{NULL}, then the default 19 | keyring is used. See also \code{\link[keyring:has_keyring_support]{has_keyring_support()}}.} 20 | } 21 | \value{ 22 | API Key value when called without \code{key}. 23 | } 24 | \description{ 25 | Get/set openrouteservice API key. 26 | } 27 | \details{ 28 | To set the key provide it in the \code{key} argument. To retrieve the current 29 | value call the function with \code{key} unset. 30 | 31 | Typically the key is saved in the system credential store. Once the key is 32 | defined, it persists in the keyring store of the operating system so it 33 | doesn't need to be set again in a new R session. 34 | 35 | Internally the function uses \verb{\link[keyring]\{key_set\}} and 36 | \verb{\link[keyring]\{key_get\}}. The use of keyring package can be bypassed by 37 | providing the key in the environment variable ORS_API_KEY. The value from the 38 | environment variable takes precedence over the value stored in the system 39 | credential store. The default environment variable name used to retrieve the 40 | openrouteservice api key can be overridden by specifying it in 41 | \code{options("openrouteservice.api_key_env")}. 42 | } 43 | \author{ 44 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 45 | } 46 | -------------------------------------------------------------------------------- /man/ors_directions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/directions.R 3 | \name{ors_directions} 4 | \alias{ors_directions} 5 | \title{Openrouteservice Directions} 6 | \usage{ 7 | ors_directions( 8 | coordinates, 9 | profile = ors_profile(), 10 | format = c("geojson", "json", "gpx"), 11 | ..., 12 | api_key = ors_api_key(), 13 | output = c("parsed", "text", "sf") 14 | ) 15 | } 16 | \arguments{ 17 | \item{coordinates}{List of \verb{longitude, latitude} coordinate pairs visited in order, alternatively a two column \code{matrix} or \code{data.frame}.} 18 | 19 | \item{profile}{Route profile, defaults to \code{"driving-car"}.} 20 | 21 | \item{format}{Response format, defaults to \code{"geojson"}} 22 | 23 | \item{...}{Optional parameters as described \href{https://openrouteservice.org/dev/#/api-docs/v2/directions/{profile}/post}{here}} 24 | 25 | \item{api_key}{Character scalar containing openrouteservice API key} 26 | 27 | \item{output}{Output format. By default the response is being parsed to a list-based R object} 28 | } 29 | \value{ 30 | Route between two or more locations in the selected \code{format} structured according to \code{output}: 31 | 32 | \itemize{ 33 | \item for \code{"text"}, a character vector of length 1 re-encoded to UTF-8. 34 | } 35 | 36 | \itemize{ 37 | \item for \code{"parsed"}, a parsed R object. 38 | } 39 | 40 | \itemize{ 41 | \item for \code{"sf"}, a simple features \code{\link[sf]{sf}} object. 42 | } 43 | } 44 | \description{ 45 | Get directions for different modes of transport. 46 | } 47 | \examples{ 48 | # These examples might require interaction to query the local keyring, or 49 | # might fail due to network issues, so they are not run by default 50 | \dontrun{ 51 | coordinates <- list(c(8.34234, 48.23424), c(8.34423, 48.26424)) 52 | 53 | # simple call 54 | try( ors_directions(coordinates, preference="fastest") ) 55 | 56 | # customized options 57 | try( ors_directions(coordinates, profile="cycling-mountain", elevation=TRUE) ) 58 | 59 | # list of locations as `data.frame` output as simple features `sf` object 60 | locations <- data.frame(lng = c(8.34234, 8.327807, 8.34423), 61 | lat = c(48.23424, 48.239368, 48.26424)) 62 | try( ors_directions(locations, output = "sf") ) 63 | } 64 | } 65 | \author{ 66 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 67 | } 68 | -------------------------------------------------------------------------------- /man/ors_elevation.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/elevation.R 3 | \name{ors_elevation} 4 | \alias{ors_elevation} 5 | \title{Openrouteservice Elevation} 6 | \usage{ 7 | ors_elevation( 8 | format_in = c("geojson", "point", "polyline", "encodedpolyline", "encodedpolyline6"), 9 | geometry, 10 | format_out = format_in, 11 | ..., 12 | api_key = ors_api_key(), 13 | output = c("parsed", "text", "sf") 14 | ) 15 | } 16 | \arguments{ 17 | \item{format_in}{input format} 18 | 19 | \item{geometry}{\verb{longitude, latitude} coordinate pairs} 20 | 21 | \item{format_out}{output format} 22 | 23 | \item{...}{Optional parameters as described \href{https://openrouteservice.org/dev/#/api-docs/elevation}{here}} 24 | 25 | \item{api_key}{Character scalar containing openrouteservice API key} 26 | 27 | \item{output}{Output format. By default the response is being parsed to a list-based R object} 28 | } 29 | \value{ 30 | 3D point or line geometry structured according to \code{output}: 31 | 32 | \itemize{ 33 | \item for \code{"text"}, a character vector of length 1 re-encoded to UTF-8. 34 | } 35 | 36 | \itemize{ 37 | \item for \code{"parsed"}, a parsed R object. 38 | } 39 | 40 | \itemize{ 41 | \item for \code{"sf"}, a simple features \code{\link[sf]{sf}} object. 42 | } 43 | } 44 | \description{ 45 | Get elevation data for points or lines 46 | } 47 | \details{ 48 | A GeoJSON based service to query SRTM elevation for Point or LineString 2D 49 | geometries and return 3D geometries in various formats. 50 | } 51 | \examples{ 52 | # These examples might require interaction to query the local keyring, or 53 | # might fail due to network issues, so they are not run by default 54 | \dontrun{ 55 | # point coordinates 56 | coordinates <- c(13.349762, 38.11295) 57 | try( ors_elevation("point", coordinates) ) 58 | 59 | # geojson as input 60 | point <- '{ "type": "Point", "coordinates": [13.349762, 38.11295] }' 61 | try( ors_elevation("geojson", point) ) 62 | 63 | # line geometry returned as encoded polyline 64 | coordinates <- list( 65 | c(13.349762, 38.11295), 66 | c(12.638397, 37.645772) 67 | ) 68 | try( ors_elevation("polyline", coordinates, format_out = "encodedpolyline") ) 69 | } 70 | } 71 | \author{ 72 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 73 | } 74 | -------------------------------------------------------------------------------- /man/ors_export.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/export.R 3 | \name{ors_export} 4 | \alias{ors_export} 5 | \title{Openrouteservice Export} 6 | \usage{ 7 | ors_export( 8 | bbox, 9 | profile = ors_profile(), 10 | ..., 11 | api_key = ors_api_key(), 12 | output = c("parsed", "text") 13 | ) 14 | } 15 | \arguments{ 16 | \item{bbox}{List of \verb{longitude, latitude} coordinate pairs defining the SW and NE corners of a rectangular area of interest, alternatively a two column \code{matrix} or \code{data.frame}.} 17 | 18 | \item{profile}{Route profile, defaults to \code{"driving-car"}.} 19 | 20 | \item{...}{Optional parameters as described \href{https://openrouteservice.org/dev/#/api-docs/v2/export/{profile}/post}{here}} 21 | 22 | \item{api_key}{Character scalar containing openrouteservice API key} 23 | 24 | \item{output}{Output format. By default the response is being parsed to a list-based R object} 25 | } 26 | \value{ 27 | Lists of graph nodes and edges contained in the provided bounding box and relevant for the given routing profile. The edge property \code{weight} represents travel time in seconds. The response is structured according to \code{output}: 28 | 29 | \itemize{ 30 | \item for \code{"text"}, a character vector of length 1 re-encoded to UTF-8. 31 | } 32 | 33 | \itemize{ 34 | \item for \code{"parsed"}, a parsed R object. 35 | } 36 | } 37 | \description{ 38 | Export the base graph for different modes of transport. 39 | } 40 | \examples{ 41 | \dontrun{ 42 | bbox <- list( 43 | c(8.681495, 49.41461), 44 | c(8.686507, 49.41943) 45 | ) 46 | 47 | res <- ors_export(bbox) 48 | } 49 | } 50 | \author{ 51 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 52 | } 53 | -------------------------------------------------------------------------------- /man/ors_geocode.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geocode.R 3 | \name{ors_geocode} 4 | \alias{ors_geocode} 5 | \title{Openrouteservice Geocoding} 6 | \usage{ 7 | ors_geocode( 8 | query, 9 | location, 10 | ..., 11 | api_key = ors_api_key(), 12 | output = c("parsed", "text", "sf") 13 | ) 14 | } 15 | \arguments{ 16 | \item{query}{Name of location, street address or postal code. For a 17 | structured geocoding request a named list of parameters.} 18 | 19 | \item{location}{Coordinates to be inquired provided in the form \code{c(longitude, latitude)}} 20 | 21 | \item{...}{Optional parameters as described \href{https://openrouteservice.org/dev/#/api-docs/geocode}{here}} 22 | 23 | \item{api_key}{Character scalar containing openrouteservice API key} 24 | 25 | \item{output}{Output format. By default the response is being parsed to a list-based R object} 26 | } 27 | \value{ 28 | Geocoding: a JSON formatted list of objects corresponding to the 29 | search input. Reverse geocoding: the next enclosing object with an address 30 | tag which surrounds the given coordinate. 31 | } 32 | \description{ 33 | Resolve input coordinates to addresses and vice versa. 34 | } 35 | \details{ 36 | This endpoint can be used for geocoding (specified \code{query}) and reverse 37 | geocoding requests (specified \code{location}). Either \code{query} or \code{location} has 38 | to be specified for a valid request. If both parameters are specified 39 | location takes precedence. 40 | } 41 | \examples{ 42 | # These examples might require interaction to query the local keyring, or 43 | # might fail due to network issues, so they are not run by default 44 | \dontrun{ 45 | ## locations of Heidelberg around the globe 46 | x <- ors_geocode("Heidelberg") 47 | 48 | ## set the number of results returned 49 | x <- ors_geocode("Heidelberg", size = 1) 50 | 51 | ## search within a particular country 52 | ors_geocode("Heidelberg", boundary.country = "DE") 53 | 54 | ## structured geocoding 55 | x <- ors_geocode(list(locality="Heidelberg", county="Heidelberg")) 56 | 57 | ## reverse geocoding 58 | location <- x$features[[1L]]$geometry$coordinates 59 | y <- ors_geocode(location = location, layers = "locality", size = 1) 60 | } 61 | } 62 | \author{ 63 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 64 | } 65 | -------------------------------------------------------------------------------- /man/ors_isochrones.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/isochrones.R 3 | \name{ors_isochrones} 4 | \alias{ors_isochrones} 5 | \title{Openrouteservice Isochrones} 6 | \usage{ 7 | ors_isochrones( 8 | locations, 9 | profile = ors_profile(), 10 | range = 60, 11 | ..., 12 | api_key = ors_api_key(), 13 | output = c("parsed", "text", "sf") 14 | ) 15 | } 16 | \arguments{ 17 | \item{locations}{List of \verb{longitude, latitude} coordinate pairs, alternatively a two column \code{matrix} or \code{data.frame}.} 18 | 19 | \item{profile}{Route profile, defaults to \code{"driving-car"}.} 20 | 21 | \item{range}{Maximum range value of the analysis in seconds for time and 22 | meters for distance. Alternatively a comma separated list of specific 23 | single range values.} 24 | 25 | \item{...}{Optional parameters as described \href{https://openrouteservice.org/dev/#/api-docs/v2/isochrones/{profile}/post}{here}} 26 | 27 | \item{api_key}{Character scalar containing openrouteservice API key} 28 | 29 | \item{output}{Output format. By default the response is being parsed to a list-based R object} 30 | } 31 | \value{ 32 | A GeoJSON object containing a FeatureCollection of Polygons 33 | 34 | \itemize{ 35 | \item for \code{"text"}, a character vector of length 1 re-encoded to UTF-8. 36 | } 37 | 38 | \itemize{ 39 | \item for \code{"parsed"}, a parsed R object. 40 | } 41 | 42 | \itemize{ 43 | \item for \code{"sf"}, a simple features \code{\link[sf]{sf}} object. 44 | } 45 | } 46 | \description{ 47 | Obtain areas of reachability from given locations. 48 | } 49 | \details{ 50 | The Isochrone Service supports time and distance analyses for one single or 51 | multiple locations. You may also specify the isochrone interval or provide 52 | multiple exact isochrone range values. 53 | } 54 | \examples{ 55 | # These examples might require interaction to query the local keyring, or 56 | # might fail due to network issues, so they are not run by default 57 | \dontrun{ 58 | ors_isochrones(c(8.34234, 48.23424), interval=20) 59 | 60 | locations <- list(c(8.681495, 49.41461), c(8.686507,49.41943)) 61 | ors_isochrones(locations, range=c(300, 200)) 62 | } 63 | } 64 | \author{ 65 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 66 | } 67 | -------------------------------------------------------------------------------- /man/ors_matrix.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/matrix.R 3 | \name{ors_matrix} 4 | \alias{ors_matrix} 5 | \title{Openrouteservice Matrix} 6 | \usage{ 7 | ors_matrix( 8 | locations, 9 | profile = ors_profile(), 10 | ..., 11 | api_key = ors_api_key(), 12 | output = c("parsed", "text") 13 | ) 14 | } 15 | \arguments{ 16 | \item{locations}{List of \verb{longitude, latitude} coordinate pairs, alternatively a two column \code{matrix} or \code{data.frame}.} 17 | 18 | \item{profile}{Route profile, defaults to \code{"driving-car"}.} 19 | 20 | \item{...}{Optional parameters as described \href{https://openrouteservice.org/dev/#/api-docs/v2/matrix/{profile}/post}{here}} 21 | 22 | \item{api_key}{Character scalar containing openrouteservice API key} 23 | 24 | \item{output}{Output format. By default the response is being parsed to a list-based R object} 25 | } 26 | \value{ 27 | Duration or distance matrix for multiple source and destination 28 | 29 | \itemize{ 30 | \item for \code{"text"}, a character vector of length 1 re-encoded to UTF-8. 31 | } 32 | 33 | \itemize{ 34 | \item for \code{"parsed"}, a parsed R object. 35 | } 36 | } 37 | \description{ 38 | Obtain one-to-many, many-to-one and many-to-many matrices for time and 39 | distance. 40 | } 41 | \examples{ 42 | # These examples might require interaction to query the local keyring, or 43 | # might fail due to network issues, so they are not run by default 44 | \dontrun{ 45 | coordinates <- list( 46 | c(9.970093, 48.477473), 47 | c(9.207916, 49.153868), 48 | c(37.573242, 55.801281), 49 | c(115.663757,38.106467) 50 | ) 51 | 52 | # query for duration and distance in km 53 | res <- ors_matrix(coordinates, metrics = c("duration", "distance"), units = "km") 54 | 55 | # duration in hours 56 | res$durations / 3600 57 | 58 | # distance in km 59 | res$distances 60 | } 61 | } 62 | \author{ 63 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 64 | } 65 | -------------------------------------------------------------------------------- /man/ors_optimization.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/optimization.R 3 | \name{ors_optimization} 4 | \alias{ors_optimization} 5 | \alias{jobs} 6 | \alias{vehicles} 7 | \title{Openrouteservice Optimization} 8 | \usage{ 9 | ors_optimization( 10 | jobs, 11 | vehicles, 12 | matrix = NULL, 13 | ..., 14 | api_key = ors_api_key(), 15 | output = c("parsed", "text") 16 | ) 17 | 18 | jobs( 19 | id, 20 | location, 21 | location_index, 22 | service, 23 | amount, 24 | skills, 25 | priority, 26 | time_windows 27 | ) 28 | 29 | vehicles( 30 | id, 31 | profile, 32 | start, 33 | start_index, 34 | end, 35 | end_index, 36 | capacity, 37 | skills, 38 | time_window 39 | ) 40 | } 41 | \arguments{ 42 | \item{jobs}{\code{data.frame} describing the places to visit} 43 | 44 | \item{vehicles}{\code{data.frame} describing the available vehicles} 45 | 46 | \item{matrix}{Optional two-dimensional array describing a custom travel-time 47 | matrix} 48 | 49 | \item{...}{Optional parameters as described \href{https://openrouteservice.org/dev/#/api-docs/optimization/post}{here}} 50 | 51 | \item{api_key}{Character scalar containing openrouteservice API key} 52 | 53 | \item{output}{Output format. By default the response is being parsed to a list-based R object} 54 | 55 | \item{id}{An integer used as unique identifier} 56 | 57 | \item{location}{Coordinates array} 58 | 59 | \item{location_index}{Index of relevant row and column in custom matrix} 60 | 61 | \item{service}{Job service duration (defaults to 0)} 62 | 63 | \item{amount}{An array of integers describing multidimensional quantities} 64 | 65 | \item{skills}{An array of integers defining skills} 66 | 67 | \item{priority}{An integer in the [0, 10] range describing priority level 68 | (defaults to 0)} 69 | 70 | \item{time_windows}{An array of time_window objects describing valid slots 71 | for job service start} 72 | 73 | \item{profile}{routing profile (defaults to car)} 74 | 75 | \item{start}{coordinates array} 76 | 77 | \item{start_index}{index of relevant row and column in custom matrix} 78 | 79 | \item{end}{coordinates array} 80 | 81 | \item{end_index}{index of relevant row and column in custom matrix} 82 | 83 | \item{capacity}{an array of integers describing multidimensional quantities} 84 | 85 | \item{time_window}{a time_window object describing working hours} 86 | } 87 | \value{ 88 | Solution computed by the optimization endpoint formatted as described \href{https://github.com/VROOM-Project/vroom/blob/master/docs/API.md#output}{here} and structured according to \code{output}: 89 | 90 | \itemize{ 91 | \item for \code{"text"}, a character vector of length 1 re-encoded to UTF-8. 92 | } 93 | 94 | \itemize{ 95 | \item for \code{"parsed"}, a parsed R object. 96 | } 97 | } 98 | \description{ 99 | Optimize a fleet of vehicles on a number of jobs. For more information, see 100 | the 101 | \href{https://github.com/VROOM-Project/vroom/blob/master/docs/API.md}{Vroom 102 | project API documentation}. 103 | 104 | The helper functions \code{jobs()} and \code{vehicles()} create 105 | data.frames which can be used as arguments to \code{ors_optimization()}. 106 | } 107 | \examples{ 108 | # These examples might require interaction to query the local keyring, or 109 | # might fail due to network issues, so they are not run by default 110 | \dontrun{ 111 | home_base <- c(2.35044, 48.71764) 112 | 113 | vehicles <- vehicles( 114 | id = 1:2, 115 | profile = "driving-car", 116 | start = home_base, 117 | end = home_base, 118 | capacity = 4, 119 | skills = list(c(1, 14), c(2, 14)), 120 | time_window = c(28800, 43200) 121 | ) 122 | 123 | locations <- list( 124 | c(1.98935, 48.701), 125 | c(2.03655, 48.61128), 126 | c(2.39719, 49.07611), 127 | c(2.41808, 49.22619), 128 | c(2.28325, 48.5958), 129 | c(2.89357, 48.90736) 130 | ) 131 | 132 | jobs <- jobs( 133 | id = 1:6, 134 | service = 300, 135 | amount = 1, 136 | location = locations, 137 | skills = list(1, 1, 2, 2, 14, 14) 138 | ) 139 | 140 | try( ors_optimization(jobs, vehicles) ) 141 | } 142 | } 143 | \author{ 144 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 145 | } 146 | -------------------------------------------------------------------------------- /man/ors_pois.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pois.R 3 | \name{ors_pois} 4 | \alias{ors_pois} 5 | \title{Openrouteservice POIs} 6 | \usage{ 7 | ors_pois( 8 | request = c("pois", "stats", "list"), 9 | geometry, 10 | ..., 11 | api_key = ors_api_key(), 12 | output = c("parsed", "text", "sf") 13 | ) 14 | } 15 | \arguments{ 16 | \item{request}{One of the following: \code{"pois"}, \code{"stats"} or \code{"list"}} 17 | 18 | \item{geometry}{named list containing either a \code{geojson} geometry object 19 | (GeoJSON Point, LineString or Polygon) or a \code{bbox}, optionally buffered by 20 | a value provided \code{buffer}} 21 | 22 | \item{...}{Optional request attributes as described \href{https://openrouteservice.org/dev/#/api-docs/pois/post}{here}} 23 | 24 | \item{api_key}{Character scalar containing openrouteservice API key} 25 | 26 | \item{output}{Output format. By default the response is being parsed to a list-based R object} 27 | } 28 | \value{ 29 | A list of points of interest in the area specified in \code{geometry} structured according to \code{output}: 30 | 31 | \itemize{ 32 | \item for \code{"text"}, a character vector of length 1 re-encoded to UTF-8. 33 | } 34 | 35 | \itemize{ 36 | \item for \code{"parsed"}, a parsed R object. 37 | } 38 | 39 | \itemize{ 40 | \item for \code{"sf"}, a simple features \code{\link[sf]{sf}} object. Valid only for argument \code{request = "pois"}. 41 | } 42 | } 43 | \description{ 44 | Search for points of interest around points or in geometries. 45 | } 46 | \details{ 47 | There are three different request types: \code{pois}, \code{stats} and \code{list}. 48 | 49 | \code{pois} returns a GeoJSON FeatureCollection in the bounding box specified in 50 | \code{geometry$bbox} or a GeoJSON geometry provided in \code{geometry$geojson}. \code{stats} 51 | does the same but groups by categories, ultimately returning a JSON object 52 | with the absolute numbers of POIs of a certain group. 53 | 54 | \code{list} returns a list of category groups and their ids. 55 | } 56 | \examples{ 57 | # These examples might require interaction to query the local keyring, or 58 | # might fail due to network issues, so they are not run by default 59 | \dontrun{ 60 | # POI categories list 61 | ors_pois('list') 62 | 63 | # POIs around a buffered point 64 | geometry <- list(geojson = list(type = "Point", 65 | coordinates = c(8.8034, 53.0756)), 66 | buffer = 100) 67 | ors_pois(geometry = geometry) 68 | 69 | # alternative specification via bounding box 70 | ors_pois(geometry = list(bbox = list(c(8.8034, 53.0756), c(8.8034, 53.0756)), 71 | buffer = 100)) 72 | 73 | # POIs of given categories 74 | ors_pois(geometry = geometry, 75 | limit = 200, 76 | sortby = "distance", 77 | filters = list( 78 | category_ids = c(180, 245) 79 | )) 80 | 81 | # POIs of given category groups 82 | ors_pois(geometry = geometry, 83 | limit = 200, 84 | sortby = "distance", 85 | filters = list( 86 | category_group_ids = 160 87 | )) 88 | 89 | # POI Statistics 90 | ors_pois("stats", geometry = geometry) 91 | } 92 | } 93 | \author{ 94 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 95 | } 96 | -------------------------------------------------------------------------------- /man/ors_profile.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/profiles.R 3 | \name{ors_profile} 4 | \alias{ors_profile} 5 | \title{Openrouteservice Profiles} 6 | \usage{ 7 | ors_profile( 8 | mode = c("car", "hgv", "bike", "roadbike", "mtb", "e-bike", "walking", "hiking", 9 | "wheelchair") 10 | ) 11 | } 12 | \arguments{ 13 | \item{mode}{Profile label.} 14 | } 15 | \value{ 16 | Profile name, or named vector of available profiles. 17 | } 18 | \description{ 19 | List of available modes of transport. 20 | } 21 | \details{ 22 | Convenience function for specifying the profile in \code{\link[=ors_directions]{ors_directions()}}, 23 | \code{\link[=ors_isochrones]{ors_isochrones()}} and \code{\link[=ors_matrix]{ors_matrix()}}. 24 | } 25 | \examples{ 26 | # list availbale profiles 27 | ors_profile() 28 | 29 | # retrieve full profile name based on label 30 | ors_profile("car") 31 | } 32 | \seealso{ 33 | \code{\link[=ors_directions]{ors_directions()}}, \code{\link[=ors_isochrones]{ors_isochrones()}}, \code{\link[=ors_matrix]{ors_matrix()}} 34 | } 35 | \author{ 36 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 37 | } 38 | -------------------------------------------------------------------------------- /man/ors_snap.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/snap.R 3 | \name{ors_snap} 4 | \alias{ors_snap} 5 | \title{Openrouteservice Snapping} 6 | \usage{ 7 | ors_snap( 8 | locations, 9 | profile = ors_profile(), 10 | radius, 11 | format = c("geojson", "json"), 12 | ..., 13 | api_key = ors_api_key(), 14 | output = c("parsed", "text", "sf") 15 | ) 16 | } 17 | \arguments{ 18 | \item{locations}{List of \verb{longitude, latitude} coordinate pairs, alternatively a two column \code{matrix} or \code{data.frame}.} 19 | 20 | \item{profile}{Route profile, defaults to \code{"driving-car"}.} 21 | 22 | \item{radius}{Maximum radius in meters around given coordinates to search for graph edges} 23 | 24 | \item{format}{Response format, defaults to \code{"geojson"}} 25 | 26 | \item{...}{Optional parameters as described \href{https://openrouteservice.org/dev/#/api-docs/v2/snap/{profile}/post}{here}} 27 | 28 | \item{api_key}{Character scalar containing openrouteservice API key} 29 | 30 | \item{output}{Output format. By default the response is being parsed to a list-based R object} 31 | } 32 | \value{ 33 | Coordinates of snapped location(s) and distance to the original point(s) structured according to \code{output}: 34 | 35 | \itemize{ 36 | \item for \code{"text"}, a character vector of length 1 re-encoded to UTF-8. 37 | } 38 | 39 | \itemize{ 40 | \item for \code{"parsed"}, a parsed R object. 41 | } 42 | 43 | \itemize{ 44 | \item for \code{"sf"}, a simple features \code{\link[sf]{sf}} object. 45 | } 46 | } 47 | \description{ 48 | Snap coordinates to road network 49 | } 50 | \examples{ 51 | # These examples might require interaction to query the local keyring, or 52 | # might fail due to network issues, so they are not run by default 53 | \dontrun{ 54 | locations <- list( 55 | c(8.669629, 49.413025), 56 | c(8.675841, 49.418532), 57 | c(8.665144, 49.415594) 58 | ) 59 | 60 | # query for locations snapped onto the OpenStreetMap road network 61 | res <- ors_snap(locations, radius = 350) 62 | } 63 | } 64 | \author{ 65 | Andrzej Oleś \href{mailto:andrzej.oles@gmail.com}{andrzej.oles@gmail.com} 66 | } 67 | -------------------------------------------------------------------------------- /man/print.ors_api.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/api_call.R 3 | \name{print.ors_api} 4 | \alias{print.ors_api} 5 | \title{Print a Compact Summary of the API Response} 6 | \usage{ 7 | \method{print}{ors_api}(x, give.attr = FALSE, list.len = 6L, ...) 8 | } 9 | \arguments{ 10 | \item{x}{object of class \code{ors_api}.} 11 | 12 | \item{give.attr}{logical; if \code{TRUE} (default), show attributes 13 | as sub structures.} 14 | 15 | \item{list.len}{numeric; maximum number of list elements to display 16 | within a level.} 17 | 18 | \item{...}{further arguments passed to \link[utils:str]{str}.} 19 | } 20 | \value{ 21 | \code{print.ors_api} prints its argument and returns it \emph{invisibly}. 22 | } 23 | \description{ 24 | \code{print.ors_api} uses \link[utils:str]{str} to compactly display the structure 25 | of the openrouteservice API response object. 26 | } 27 | -------------------------------------------------------------------------------- /pkgdown/extra.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Open+Sans|Raleway:500,700'); 2 | 3 | body { 4 | font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 5 | } 6 | 7 | h1, h2, h3, h4, h5, h6 { 8 | font-family: "Raleway", "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | } 10 | 11 | .navbar-default { 12 | background-color: #b5152b; 13 | } 14 | 15 | .navbar-default .navbar-nav > li > a { 16 | color: #ffffff; 17 | } 18 | 19 | .navbar-brand .navbar-link { 20 | font-family: "Raleway", "Helvetica Neue", Helvetica, Arial, sans-serif; 21 | font-weight: bold; 22 | color: #ffffff; 23 | } 24 | -------------------------------------------------------------------------------- /references.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: rmarkdown::md_document 3 | bibliography: references.bib 4 | csl: references.csl 5 | nocite: '@*' 6 | --- 7 | -------------------------------------------------------------------------------- /references.bib: -------------------------------------------------------------------------------- 1 | @book{baumer2017modern, 2 | title={Modern data science with R}, 3 | author={Baumer, Benjamin S and Kaplan, Daniel T and Horton, Nicholas J}, 4 | year={2017}, 5 | publisher={Chapman and Hall/CRC} 6 | } 7 | 8 | @article{cervigni2020describing, 9 | title={Describing and mapping diversity and accessibility of the urban food environment with open data and tools}, 10 | author={Cervigni, Eleanor and Renton, Michael and McKenzie, Fiona Haslam and Hickling, Siobhan and Olaru, Doina}, 11 | journal={Applied Geography}, 12 | volume={125}, 13 | pages={102352}, 14 | year={2020}, 15 | publisher={Elsevier} 16 | } 17 | 18 | @article{petricola2022assessing, 19 | title={Assessing road criticality and loss of healthcare accessibility during floods: the case of Cyclone Idai, Mozambique 2019}, 20 | author={Petricola, Sami and Reinmuth, Marcel and Lautenbach, Sven and Hatfield, Charles and Zipf, Alexander}, 21 | journal={International journal of health geographics}, 22 | volume={21}, 23 | number={1}, 24 | pages={14}, 25 | year={2022}, 26 | publisher={Springer} 27 | } 28 | 29 | @phdthesis{weenink2022overcoming, 30 | title={Overcoming the Modifiable Areal Unit Problem (MAUP) of socio-economic variables in real estate modelling}, 31 | author={Weenink, Philibert}, 32 | year={2022} 33 | } 34 | 35 | @article{shields2022feasibility, 36 | title={Feasibility of scaling-up a community-based exercise program for young people with disability}, 37 | author={Shields, Nora and Willis, Claire and Imms, Christine and McKenzie, Georgia and Van Dorsselaer, Ben and Bruder, Andrea M and Kennedy, Rachel A and Bhowon, Yeshna and Southby, Alesha and Prendergast, Luke A and others}, 38 | journal={Disability and Rehabilitation}, 39 | volume={44}, 40 | number={9}, 41 | pages={1669--1681}, 42 | year={2022}, 43 | publisher={Taylor \& Francis} 44 | } 45 | 46 | @article{veloso2022brazilian, 47 | title={Brazilian disaster datasets and real-world instances for optimization and machine learning}, 48 | author={Veloso, Rafaela and Cespedes, Juliana and Caunhye, Aakil and Alem, Douglas}, 49 | journal={Data in brief}, 50 | volume={42}, 51 | pages={108012}, 52 | year={2022}, 53 | publisher={Elsevier} 54 | } 55 | 56 | @article{cubells2023scooter, 57 | title={E-scooter and bike-share route choice and detours: modelling the influence of built environment and sociodemographic factors}, 58 | author={Cubells, Jer{\`o}nia and Miralles-Guasch, Carme and Marquet, Oriol}, 59 | journal={Journal of transport geography}, 60 | volume={111}, 61 | pages={103664}, 62 | year={2023}, 63 | publisher={Elsevier} 64 | } 65 | 66 | @article{bhowon2023using, 67 | title={Using Geospatial Analysis to Determine the Proximity of Community Gyms for a Population-based Cohort of Young People with Cerebral Palsy}, 68 | author={Bhowon, Yeshna and Prendergast, Luke A and Taylor, Nicholas F and Shields, Nora}, 69 | journal={Physiotherapy Canada}, 70 | pages={e20220064}, 71 | year={2023}, 72 | publisher={University of Toronto Press} 73 | } 74 | 75 | @article{amato2023current, 76 | title={Current patterns of trauma center proliferation have not led to proportionate improvements in access to care or mortality after injury: An ecologic study}, 77 | author={Amato, Stas and Benson, Jamie S and Stewart, Barclay and Sarathy, Ashwini and Osler, Turner and Hosmer, David and An, Gary and Cook, Alan and Winchell, Robert J and Malhotra, Ajai K}, 78 | journal={Journal of Trauma and Acute Care Surgery}, 79 | volume={94}, 80 | number={6}, 81 | pages={755--764}, 82 | year={2023}, 83 | publisher={LWW} 84 | } 85 | 86 | @article{jain2024modeling, 87 | title={Modeling health and well-being measures using ZIP code spatial neighborhood patterns}, 88 | author={Jain, Abhi and LaValley, Michael and Dukes, Kimberly and Lane, Kevin and Winter, Michael and Spangler, Keith R and Cesare, Nina and Wang, Biqi and Rickles, Michael and Mohammed, Shariq}, 89 | journal={Scientific Reports}, 90 | volume={14}, 91 | number={1}, 92 | pages={9180}, 93 | year={2024}, 94 | publisher={Nature Publishing Group UK London} 95 | } 96 | -------------------------------------------------------------------------------- /references.csl: -------------------------------------------------------------------------------- 1 |  2 | 352 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(openrouteservice) 3 | 4 | test_check("openrouteservice") 5 | -------------------------------------------------------------------------------- /tests/testthat/helpers.R: -------------------------------------------------------------------------------- 1 | sys_name <- function() tolower(Sys.info()[["sysname"]]) 2 | 3 | on_os <- function(name) isTRUE(tolower(name) == sys_name()) 4 | 5 | mock_response <- function(status = 200L, ...) { 6 | structure( 7 | list( 8 | status_code = as.integer(status), 9 | ... 10 | ), 11 | class = "response" 12 | ) 13 | } 14 | 15 | counter <- list() 16 | 17 | mock_method <- function(..., timeframe = 2, n = 1) { 18 | cur_time <- Sys.time() 19 | if ( length(counter) ) 20 | counter <<- counter[-sapply(counter, difftime, cur_time, units="sec") < timeframe] 21 | 22 | counter <<- c(counter, as.list(cur_time)) 23 | 24 | if ( length(counter) > n) 25 | mock_response(429L) 26 | else 27 | mock_response(200L) 28 | } 29 | -------------------------------------------------------------------------------- /tests/testthat/mock_gpx.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | openrouteservice directions 5 | This is a directions instructions file as GPX, generated from openrouteservice 6 | 7 | openrouteservice 8 | 9 | 10 | https://go.openrouteservice.org/ 11 | text/html 12 | 13 | 14 | 15 | 2018Z 16 | Apache License 2.0 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /tests/testthat/print.txt: -------------------------------------------------------------------------------- 1 | 2 | List of 2 3 | $ x: int [1:3] 1 2 3 4 | $ y: chr [1:3] "a" "b" "c" 5 | -------------------------------------------------------------------------------- /tests/testthat/test-api_key.R: -------------------------------------------------------------------------------- 1 | context("Key management") 2 | 3 | on_cran <- function() { 4 | !interactive() && !isTRUE(as.logical(Sys.getenv("NOT_CRAN", "false"))) 5 | } 6 | 7 | ## record current state before starting any tests 8 | env <- Sys.getenv("ORS_API_KEY", NA); 9 | key <- tryCatch(if (on_cran()) NA else keyring::key_get("openrouteservice"), error = function(e) NA) 10 | 11 | ## restore initial state 12 | on.exit({ 13 | if ( !is.na(env) ) Sys.setenv(ORS_API_KEY = env) 14 | if ( !is.na(key) ) keyring::key_set_with_value("openrouteservice", NULL, key) 15 | }, add = TRUE) 16 | 17 | Sys.unsetenv("ORS_API_KEY") 18 | api_key_val <- "key_stored_in_keyring" 19 | 20 | test_that("Set key in keyring", { 21 | skip_on_cran() 22 | skip_on_os("linux") 23 | expect_silent(ors_api_key(api_key_val)) 24 | }) 25 | 26 | test_that("Get key from keyring", { 27 | skip_on_cran() 28 | skip_on_os("linux") 29 | expect_identical(ors_api_key(), api_key_val) 30 | }) 31 | 32 | test_that("Environment variable takes precedance over keyring", { 33 | api_key_val <- "key_stored_in_env_var" 34 | Sys.setenv(ORS_API_KEY = api_key_val) 35 | expect_identical(ors_api_key(), api_key_val) 36 | }) 37 | 38 | test_that("Use non-default environment variable for api key", { 39 | options(openrouteservice.api_key_env = "MY_API_KEY") 40 | api_key_val <- "my_api_key_value" 41 | Sys.setenv(MY_API_KEY = api_key_val) 42 | expect_identical(ors_api_key(), api_key_val) 43 | Sys.unsetenv("MY_API_KEY") 44 | }) 45 | -------------------------------------------------------------------------------- /tests/testthat/test-call_api.R: -------------------------------------------------------------------------------- 1 | context("Rate limit") 2 | 3 | test_that("Call API", { 4 | expect_identical(status_code(mock_method()), 200L) 5 | expect_identical(status_code(mock_method()), 429L) 6 | expect_identical(status_code(call_api(mock_method, list())), 200L) 7 | expect_identical(status_code(mock_method()), 429L) 8 | }) 9 | -------------------------------------------------------------------------------- /tests/testthat/test-leaflet.R: -------------------------------------------------------------------------------- 1 | context("Leaflet fitBBox") 2 | 3 | library("leaflet") 4 | 5 | m <- leaflet() 6 | 7 | lng1 <- 8 8 | lat1 <- 49 9 | lng2 <- 9 10 | lat2 <- 50 11 | 12 | test_that("Equivalent to fitBounds", { 13 | expect_identical(fitBBox(m, c(lng1, lat1, lng2, lat2)), 14 | fitBounds(m, lng1, lat1, lng2, lat2)) 15 | }) 16 | 17 | test_that("Returns unaltered map when no bbox provided", { 18 | expect_identical(fitBBox(m, NULL), m) 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-print.R: -------------------------------------------------------------------------------- 1 | context("Print method") 2 | 3 | l <- list(x = 1:3, y = letters[1:3]) 4 | obj <- structure(l, class = c("endpoint", "ors_api", class(l))) 5 | 6 | test_that("Output has expected formatting", { 7 | expect_known_output(obj, "print.txt", print = TRUE) 8 | }) 9 | 10 | null_dev <- function() if (on_os("windows")) "NUL" else "/dev/null" 11 | 12 | test_that("Print invisibly returns its argument", { 13 | sink(null_dev()) 14 | x <- withVisible(print(obj)) 15 | sink() 16 | expect_identical(x$value, obj) 17 | expect_false(x$visible) 18 | }) 19 | -------------------------------------------------------------------------------- /tests/testthat/test-query.R: -------------------------------------------------------------------------------- 1 | context("Construct query") 2 | 3 | ## record current state before starting any tests 4 | opts <- options() 5 | 6 | ## restore initial state 7 | on.exit(options(opts), add = TRUE) 8 | 9 | test_that("Encode pairs", { 10 | expect_identical(encode_pairs(list(1:2, 3:4)), c("1,2", "3,4")) 11 | expect_error(encode_pairs(1:3)) 12 | }) 13 | 14 | test_that("Collapse vectors but not lists", { 15 | x = 1:3 16 | expect_identical(collapse_vector(x, ","), "1,2,3") 17 | x = as.list(x) 18 | expect_identical(collapse_vector(x), x) 19 | }) 20 | 21 | x <- 0.123456789 22 | y <- 123.456789 23 | z <- 123456789L 24 | 25 | obj <- list(x, y, list(c(x, y), list(z))) 26 | 27 | xx <- 0.123457 28 | 29 | ref <- list(xx, y, list(c(xx, y), list(z))) 30 | 31 | test_that("Limit numerical precision of non-integer numbers", { 32 | expect_identical(limit_precision(obj, 6L), ref) 33 | }) 34 | 35 | v <- c(0.123456789, 0.987654321) 36 | 37 | api_key <- "api_key" 38 | 39 | obj <- list( 40 | locations = list(v), 41 | vector = v, 42 | options = list( 43 | scalar = "a", 44 | vector = v, 45 | avoid_polygons = list( 46 | type = "Polygon", 47 | coordinates = list(list(v, v, v)) 48 | ) 49 | ) 50 | ) 51 | 52 | ref <- list( 53 | api_key = api_key, 54 | locations = "0.123457,0.987654", 55 | vector = "0.123457|0.987654", 56 | options = structure('{"scalar":"a","vector":"0.123457|0.987654","avoid_polygons":{"type":"Polygon","coordinates":[[[0.123457,0.987654],[0.123457,0.987654],[0.123457,0.987654]]]}}', class = "json") 57 | ) 58 | 59 | res <- openrouteservice:::api_query(api_key, obj) 60 | 61 | test_that("API key is prepended to the original parameters", { 62 | expect_identical(names(res), c("api_key", names(obj))) 63 | }) 64 | 65 | test_that("API key value matches", { 66 | expect_identical(res$api_key, api_key) 67 | }) 68 | 69 | test_that("Coordinate pairs and vectors are properly encoded", { 70 | expect_identical(res$locations, ref$locations) 71 | expect_identical(res$vector, ref$vector) 72 | }) 73 | 74 | test_that("Options are encoded as json", { 75 | expect_identical(res$options, ref$options) 76 | }) 77 | -------------------------------------------------------------------------------- /tests/testthat/test-response.R: -------------------------------------------------------------------------------- 1 | context("Process response") 2 | 3 | mock_error <- mock_response( 4 | status = 400L, 5 | headers = list("Content-Type" = "application/json;charset=UTF-8"), 6 | content = charToRaw(toJSON(list(error = list(code = 123L, message = "Error message")))) 7 | ) 8 | 9 | test_that("Error response", { 10 | expect_error(process_response(mock_error)) 11 | }) 12 | 13 | mock_gpx <- paste(readLines("mock_gpx.xml"), collapse = "\n") 14 | 15 | mock_xml <- mock_response( 16 | headers = list("Content-Type" = "application/gpx+xml;charset=UTF-8"), 17 | request = list(headers = list(Accept = "application/gpx+xml")), 18 | content = charToRaw(mock_gpx) 19 | ) 20 | 21 | test_that("Parsed GPX response", { 22 | expect_equal(process_response(mock_xml, "endpoint", output = "parsed"), read_xml(mock_gpx)) 23 | }) 24 | 25 | test_that("Unparsed GPX response", { 26 | expect_identical(process_response(mock_xml, "endpoint", output = "text"), mock_gpx) 27 | }) 28 | -------------------------------------------------------------------------------- /update_web.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DOCS_DIR=docs 4 | VERSION=$(git rev-parse --short HEAD) 5 | REMOTE_URL=$(git config --get remote.origin.url) 6 | 7 | mkdir -p ${DOCS_DIR} 8 | rm -rf ${DOCS_DIR}/.git 9 | git init ${DOCS_DIR} 10 | git -C ${DOCS_DIR} checkout --orphan gh-pages 11 | git -C ${DOCS_DIR} add . 12 | git -C ${DOCS_DIR} commit --no-verify -m "Update docs for version ${VERSION}" 13 | git -C ${DOCS_DIR} remote add origin -m "gh-pages" ${REMOTE_URL} 14 | git -C ${DOCS_DIR} push --force -u origin gh-pages 15 | -------------------------------------------------------------------------------- /vignettes/openrouteservice.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Query openrouteservice from R" 3 | author: "Andrzej Oleś" 4 | date: "`r Sys.Date()`" 5 | output: 6 | rmarkdown::html_document: 7 | toc: true 8 | toc_float: true 9 | vignette: > 10 | %\VignetteIndexEntry{Query openrouteservice from R} 11 | %\VignetteEngine{knitr::rmarkdown} 12 | %\VignetteEncoding{UTF-8} 13 | --- 14 | 15 | ```{r config, include=FALSE} 16 | ## increase width for code output 17 | .options_old <- options(width = 100) 18 | ## set up knitr defaults 19 | NOT_CRAN <- identical(tolower(Sys.getenv("NOT_CRAN")), "true") 20 | knitr::opts_chunk$set(purl = NOT_CRAN, eval = NOT_CRAN, 21 | out.width = '100%', out.height = '560px') 22 | ``` 23 | 24 | ## Get started 25 | 26 | 27 | ```{r doc, include=FALSE, eval=TRUE} 28 | ## create alias 29 | doc <- openrouteservice:::doc_link 30 | ``` 31 | 32 | *openrouteservice* R package provides easy access to the 33 | [openrouteservice](https://openrouteservice.org) (ORS) API from R. It allows you 34 | to painlessly consume the following services: 35 | 36 | - `r doc('directions')` (routing) 37 | - `r doc('geocode', label='geocoding')` powered by [Pelias](https://pelias.io) 38 | - `r doc('isochrones')` (accessibility) 39 | - time-distance `r doc('matrix', label='matrices')` 40 | - `r doc('snap', label='snapping')` to OpenStreetMap ways 41 | - `r doc('export', label='exporting')` the underlying routing graph structure 42 | - `r doc('pois')` (points of interest) 43 | - SRTM `r doc('elevation')` for point and lines geometries 44 | - routing `r doc('optimization')` based on [Vroom](http://vroom-project.org/) 45 | 46 | ### Disclaimer 47 | 48 | By using this package, you agree to the ORS [terms and 49 | conditions](https://openrouteservice.org/terms-of-service/). 50 | 51 | ### Installation 52 | 53 | The latest release version can be readily obtained from CRAN via a call to 54 | 55 | ```{r cran, eval=FALSE} 56 | install.packages("openrouteservice") 57 | ``` 58 | 59 | For running the current development version from GitHub it is recommended to use 60 | [pak](https://CRAN.R-project.org/package=pak), as it handles the installation of 61 | all the necessary packages and their system dependencies automatically. 62 | 63 | ```{r installation, eval=FALSE} 64 | # install.packages("pak") 65 | pak::pak("GIScience/openrouteservice-r") 66 | ``` 67 | 68 | 69 | ### Setting up API key 70 | 71 | In order to start using ORS services you first need to set up your personal API 72 | key, which you can `r openrouteservice:::signup_url("get for free")`. 73 | Once you are signed up, go to https://openrouteservice.org/dev/#/home -> `TOKENS`. At the bottom of the page you can request a free token (name can be anything). 74 | 75 | ```{r api_key, eval=FALSE} 76 | library(openrouteservice) 77 | 78 | ors_api_key("") 79 | ``` 80 | 81 | This will save the key in the default keyring of your system credential store. 82 | Once the key is defined, it persists in the keyring store of the operating 83 | system. This means that it survives beyond the termination of the R session, so 84 | you don't need to set it again each time you start a new R session. To retrieve 85 | the key just call `ors_api_key()` without the `key` argument. 86 | 87 | Alternatively, they key can be provided in the environment variable 88 | `ORS_API_KEY`. The value from the environment variable takes precedence over the 89 | former approach allowing to bypass the keyring infrastructure. 90 | 91 | 92 | ## Directions 93 | 94 | `ors_directions()` interfaces the ORS directions service to compute routes 95 | between given `coordinates`. 96 | 97 | ```{r directions} 98 | library(openrouteservice) 99 | 100 | coordinates <- list(c(8.34234, 48.23424), c(8.34423, 48.26424)) 101 | 102 | x <- ors_directions(coordinates) 103 | ``` 104 | 105 | Way points can be provided as a list of coordinate pairs `c(lon, lat)`, or a 106 | 2-column matrix-like object such as a data frame. 107 | 108 | ```{r data_frame} 109 | coordinates <- data.frame(lon = c(8.34234, 8.34423), lat = c(48.23424, 48.26424)) 110 | ``` 111 | 112 | The response formatting defaults to geoJSON which allows to easily 113 | [visualize](https://rstudio.github.io/leaflet/json.html#working-with-raw-geojsontopojson) 114 | it with e.g. [leaflet](https://CRAN.R-project.org/package=leaflet). 115 | 116 | ```{r leaflet} 117 | library(leaflet) 118 | 119 | leaflet() %>% 120 | addTiles() %>% 121 | addGeoJSON(x, fill=FALSE) %>% 122 | fitBBox(x$bbox) 123 | ``` 124 | 125 | Other output formats, such as GPX, can be specified in the argument `format`. 126 | Note that plain JSON response returns the geometry as [Google's encoded 127 | polyline](https://developers.google.com/maps/documentation/utilities/polylinealgorithm), 128 | 129 | ```{r encodedpolyline} 130 | x <- ors_directions(coordinates, format = "json") 131 | 132 | geometry <- x$routes[[1]]$geometry 133 | str(geometry) 134 | ``` 135 | 136 | so an additional postprocessing step might be necessary. 137 | 138 | ```{r googlepolyline} 139 | library(googlePolylines) 140 | str(decode(geometry)) 141 | ``` 142 | 143 | The API offers a wide range of `profile`s for multiple modes of transport, such 144 | as: car, heavy vehicle, different bicycle types, walking, hiking and wheelchair. 145 | These can be listed with 146 | 147 | ```{r profiles} 148 | ors_profile() 149 | ``` 150 | 151 | Each of these modes uses a carefully compiled street network to suite the 152 | profiles requirements. 153 | 154 | ```{r bicycle} 155 | x <- ors_directions(coordinates, profile="cycling-mountain") 156 | 157 | leaflet() %>% 158 | addTiles() %>% 159 | addGeoJSON(x, fill=FALSE) %>% 160 | fitBBox(x$bbox) 161 | ``` 162 | 163 | Any optional `r openrouteservice:::doc_link('directions', 'query parameters')` 164 | can be specified by providing them as additional `...` arguments to 165 | `ors_directions`. For example, in order to plot the elevation profile of a route 166 | colored by steepness use `elevation = TRUE` to add height to the coordinates of 167 | the points along the route and query for steepness in `extra_info`. 168 | 169 | ```{r cycling_mountain, message=FALSE} 170 | library("sf") 171 | 172 | x <- ors_directions(coordinates, profile = "cycling-mountain", elevation = TRUE, 173 | extra_info = "steepness", output = "sf") 174 | 175 | height <- st_geometry(x)[[1]][, 3] 176 | ``` 177 | 178 | Here we use [simple features](https://CRAN.R-project.org/package=sf) output for 179 | the sake of easy postprocessing which includes finding the length of individual 180 | route segments and their distance relative to the starting point. These can be 181 | computed with `st_distance()` upon converting the `LINESTRING` to a list of 182 | `POINT`s, 183 | 184 | ```{r segments} 185 | points <- st_cast(st_geometry(x), "POINT") 186 | n <- length(points) 187 | segments <- cumsum(st_distance(points[-n], points[-1], by_element = TRUE)) 188 | ``` 189 | 190 | while their steepness can be extracted from the requested metadata. 191 | 192 | ```{r steepness} 193 | steepness <- x$extras$steepness$values 194 | steepness <- rep(steepness[,3], steepness[,2]-steepness[,1]) 195 | steepness <- factor(steepness, -5:5) 196 | 197 | palette = setNames(rev(RColorBrewer::brewer.pal(11, "RdYlBu")), levels(steepness)) 198 | ``` 199 | 200 | For the final plot we use [ggplot2](https://CRAN.R-project.org/package=ggplot2) 201 | in combinations with [units](https://CRAN.R-project.org/package=units) which 202 | supports handling of length units associated with the data. 203 | 204 | ```{r elevation_profile, fig.dim=c(10, 5), message=FALSE, out.height='100%'} 205 | library("ggplot2") 206 | #library("ggforce") 207 | library("units") 208 | 209 | units(height) <- as_units("m") 210 | 211 | df <- data.frame(x1 = c(set_units(0, "m"), segments[-(n-1)]), 212 | x2 = segments, 213 | y1 = height[-n], 214 | y2 = height[-1], 215 | steepness) 216 | 217 | y_ran = range(height) * c(0.9, 1.1) 218 | 219 | n = n-1 220 | 221 | df2 = data.frame(x = c(df$x1, df$x2, df$x2, df$x1), 222 | y = c(rep(y_ran[1], 2*n), df$y2, df$y1), 223 | steepness, 224 | id = 1:n) 225 | 226 | ggplot() + theme_bw() + 227 | geom_segment(data = df, aes(x1, y1, xend = x2, yend = y2), linewidth = 1) + 228 | geom_polygon(data = df2, aes(x, y, group = id), fill = "white") + 229 | geom_polygon(data = df2, aes(x, y , group = id, fill = steepness)) + 230 | scale_fill_manual(values = alpha(palette, 0.8), drop = FALSE) + 231 | scale_x_units(unit = "km", expand = c(0,0)) + 232 | scale_y_units(expand = c(0,0), limits = y_ran) + 233 | labs(x = "Distance", y = "Height") 234 | ``` 235 | 236 | Advanced `options` are natively formatted as JSON objects, but can be passed as 237 | their R list representation. 238 | 239 | ```{r bicycle-avoid} 240 | polygon = list( 241 | type = "Polygon", 242 | coordinates = list( 243 | list( 244 | c(8.330469, 48.261570), 245 | c(8.339052, 48.261570), 246 | c(8.339052, 48.258227), 247 | c(8.330469, 48.258227), 248 | c(8.330469, 48.261570) 249 | ) 250 | ), 251 | properties = "" 252 | ) 253 | 254 | options <- list( 255 | avoid_polygons = polygon 256 | ) 257 | 258 | x <- ors_directions(coordinates, profile="cycling-mountain", options=options) 259 | 260 | leaflet() %>% 261 | addTiles() %>% 262 | addGeoJSON(polygon, color="#F00") %>% 263 | addGeoJSON(x, fill=FALSE) %>% 264 | fitBBox(x$bbox) 265 | ``` 266 | 267 | 268 | ## Isochrones 269 | 270 | Reachability has become a crucial component for many businesses from all 271 | different kinds of domains. `ors_isochrones()` helps you to determine which 272 | areas can be reached from certain location(s) in a given time or travel 273 | distance. The reachability areas are returned as contours of polygons. Next to 274 | the `range` provided in seconds or meters you may as well specify the 275 | corresponding `interval`s. The list of optional arguments to `ors_isochrones()` 276 | is similar as to `ors_directions()`. 277 | 278 | ```{r isochrones_ranges} 279 | library(mapview) 280 | 281 | # embed data in the output file 282 | mapviewOptions(fgb = FALSE) 283 | 284 | coordinates <- data.frame(lon = c(8.34234, 8.34234), lat = c(48.23424, 49.23424)) 285 | 286 | ## 30 minutes range split into 10 minute intervals 287 | res <- ors_isochrones(coordinates, range = 1800, interval = 600, output = "sf") 288 | res 289 | 290 | values <- levels(factor(res$value)) 291 | ranges <- split(res, values) 292 | ranges <- ranges[rev(values)] 293 | 294 | names(ranges) <- sprintf("%s min", as.numeric(names(ranges))/60) 295 | 296 | mapview(ranges, alpha.regions = 0.2, homebutton = FALSE, legend = FALSE) 297 | ``` 298 | 299 | Here we have used `sf` output for the sake of some further postprocessing and 300 | visualization. By grouping the isochrones according to ranges we gain the 301 | ability of toggling individual ranges when displayed in 302 | [mapview](https://CRAN.R-project.org/package=mapview). Another option could be 303 | to group by locations. The following example illustrates a possible approach to 304 | applying a custom color palette to the non-overlapping parts of isochrones. 305 | 306 | ```{r isochrones_colors} 307 | locations = split(res, res$group_index) 308 | 309 | locations <- lapply(locations, function(loc) { 310 | g <- st_geometry(loc) 311 | g[-which.min(values)] <- st_sfc(Map(st_difference, 312 | g[match(values[-which.min(values)], loc$value)], 313 | g[match(values[-which.max(values)], loc$value)])) 314 | st_geometry(loc) <- g 315 | loc 316 | }) 317 | 318 | isochrones <- unsplit(locations, res$group_index) 319 | 320 | pal <- setNames(heat.colors(length(values)), values) 321 | mapview(isochrones, zcol = "value", col = pal, col.regions = pal, 322 | alpha.regions = 0.5, homebutton = FALSE) 323 | ``` 324 | 325 | ## Matrix 326 | 327 | One to many, many to many or many to one: `ors_matrix()` allows you to obtain 328 | aggregated time and distance information between a set of locations (origins and 329 | destinations). Unlike `ors_directions()` it does not return detailed route 330 | information. But you may still specify the transportation mode and compute 331 | routes which adhere to certain restrictions, such as avoiding specific road 332 | types or object characteristics. 333 | 334 | ```{r matrix} 335 | coordinates <- list( 336 | c(9.970093, 48.477473), 337 | c(9.207916, 49.153868), 338 | c(37.573242, 55.801281), 339 | c(115.663757,38.106467) 340 | ) 341 | 342 | # query for duration and distance in km 343 | res <- ors_matrix(coordinates, metrics = c("duration", "distance"), units = "km") 344 | 345 | # duration in hours 346 | (res$durations / 3600) %>% round(1) 347 | 348 | # distance in km 349 | res$distances %>% round 350 | ``` 351 | 352 | ## Geocoding 353 | 354 | `ors_geocode()` transforms a description of a location provided in `query`, such 355 | as the place's name, street address or postal code, into a normalized 356 | description of the location with a point geometry. Additionally, it offers 357 | reverse geocoding which does exactly the opposite: It returns the next enclosing 358 | object which surrounds the coordinates of the given `location`. To obtain more 359 | relevant results you may also set a radius of tolerance around the requested 360 | coordinates. 361 | 362 | ```{r geocode} 363 | ## locations of Heidelberg around the globe 364 | x <- ors_geocode("Heidelberg") 365 | 366 | leaflet() %>% 367 | addTiles() %>% 368 | addGeoJSON(x) %>% 369 | fitBBox(x$bbox) 370 | 371 | ## set the number of results returned 372 | x <- ors_geocode("Heidelberg", size = 1) 373 | 374 | ## search within a particular country 375 | x <- ors_geocode("Heidelberg", boundary.country = "DE") 376 | 377 | ## structured geocoding 378 | x <- ors_geocode(list(locality="Heidelberg", county="Heidelberg")) 379 | 380 | ## reverse geocoding 381 | location <- x$features[[1L]]$geometry$coordinates 382 | 383 | y <- ors_geocode(location = location, layers = "locality", size = 1) 384 | ``` 385 | 386 | 387 | ## POIs 388 | 389 | This service allows you to find places of interest around or within given 390 | geographic coordinates. You may search for given features around a point, path 391 | or even within a polygon specified in `geometry`. To list all the available POI 392 | categories use `ors_pois('list')`. 393 | 394 | ```{r pois} 395 | geometry <- list( 396 | geojson = list( 397 | type = "Point", 398 | coordinates = c(8.8034, 53.0756) 399 | ), 400 | buffer = 500 401 | ) 402 | 403 | ors_pois( 404 | request = 'pois', 405 | geometry = geometry, 406 | limit = 2000, 407 | sortby = "distance", 408 | filters = list( 409 | category_ids = 488, 410 | wheelchair = "yes" 411 | ), 412 | output = "sf" 413 | ) 414 | ``` 415 | 416 | You can gather statistics on the amount of certain POIs in an area by using 417 | `request='stats'`. 418 | 419 | ```{r stats} 420 | ors_pois( 421 | request = 'stats', 422 | geometry = geometry, 423 | limit = 2000, 424 | sortby = "distance", 425 | filters = list(category_ids = 488) 426 | ) 427 | ``` 428 | 429 | 430 | ## Elevation 431 | 432 | Given a point or line geometry you can use `ors_elevation` to query for its 433 | elevation. 434 | 435 | ```{r elevation} 436 | x <- ors_geocode("Königstuhl", output = "sf") 437 | 438 | ors_elevation("point", st_coordinates(x)) 439 | ``` 440 | 441 | 442 | ## Optimization 443 | 444 | The optimization endpoint solves the [vehicle routing 445 | problem](https://en.wikipedia.org/wiki/Vehicle_routing_problem) (VRP) of finding 446 | an optimal set of routes for a fleet of vehicles to traverse in order to deliver 447 | to a given set of locations. The service is based on 448 | [Vroom](https://github.com/VROOM-Project/vroom) and can be used to schedule 449 | multiple vehicles and jobs respecting time windows, capacities and required 450 | skills. VRP generalizes the classic [traveling salesman 451 | problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) of finding 452 | the fastest or shortest possible route that visits a given list of locations. 453 | 454 | The following example involves a 2-vehicle fleet carrying out deliveries across 455 | 6 locations. 456 | 457 | ```{r vehicles} 458 | home_base <- data.frame(lon = 2.370658, lat = 48.721666) 459 | 460 | vehicles = vehicles( 461 | id = 1:2, 462 | profile = "driving-car", 463 | start = home_base, 464 | end = home_base, 465 | capacity = 4, 466 | skills = list(c(1, 14), c(2, 14)), 467 | time_window = c(28800, 43200) 468 | ) 469 | ``` 470 | 471 | Both `vehicles` share the `start`/`end` points and have the same `capacity`, but 472 | differ in the set of `skills` assigned. We are interested in using them to serve 473 | a number of `jobs` with certain `skills` requirements between `locations`. These 474 | skills are mandatory, which means a given job can only be served by a vehicle 475 | that has all its required skills. 476 | 477 | ```{r jobs} 478 | locations <- list( 479 | c(1.98806, 48.705), 480 | c(2.03655, 48.61128), 481 | c(2.39719, 49.07611), 482 | c(2.41808, 49.22619), 483 | c(2.28325, 48.5958), 484 | c(2.89357, 48.90736) 485 | ) 486 | 487 | jobs = jobs( 488 | id = 1:6, 489 | service = 300, 490 | amount = 1, 491 | location = locations, 492 | skills = list(1, 1, 2, 2, 14, 14) 493 | ) 494 | ``` 495 | 496 | The helper functions `vehicles` and `jobs` produce `data.frame`s which have the 497 | format appropriate for `ors_optimization`. Route geometries are enabled by 498 | setting the corresponding flag in `options`. 499 | 500 | ```{r optimization} 501 | res <- ors_optimization(jobs, vehicles, options = list(g = TRUE)) 502 | ``` 503 | 504 | The geometries are returned as [Google's encoded 505 | polylines](https://developers.google.com/maps/documentation/utilities/polylinealgorithm), 506 | so for visualization in leaflet they need to be decoded. Furthermore, we extract 507 | the job locations from the response such that we can label them in the order in 508 | which they are visited along the routes. 509 | 510 | ```{r} 511 | lapply(res$routes, with, { 512 | list( 513 | geometry = googlePolylines::decode(geometry)[[1L]], 514 | locations = lapply(steps, with, if (type=="job") location) %>% 515 | do.call(rbind, .) %>% data.frame %>% setNames(c("lon", "lat")) 516 | ) 517 | }) -> routes 518 | 519 | ## Helper function to add a list of routes and their ordered waypoints 520 | addRoutes <- function(map, routes, colors) { 521 | routes <- mapply(c, routes, color = colors, SIMPLIFY = FALSE) 522 | f <- function (map, route) { 523 | with(route, { 524 | labels <- sprintf("%s", 1:nrow(locations)) 525 | markers <- awesomeIcons(markerColor = color, text = labels, fontFamily = "arial") 526 | map %>% 527 | addPolylines(data = geometry, lng = ~lon, lat = ~lat, col = ~color) %>% 528 | addAwesomeMarkers(data = locations, lng = ~lon, lat = ~lat, icon = markers) 529 | }) 530 | } 531 | Reduce(f, routes, map) 532 | } 533 | 534 | leaflet() %>% 535 | addTiles() %>% 536 | addAwesomeMarkers(data = home_base, icon = awesomeIcons("home")) %>% 537 | addRoutes(routes, c("purple", "green")) 538 | ``` 539 | 540 | 541 | ```{r cleanup, include=FALSE} 542 | ## restore user's options 543 | options(.options_old) 544 | ``` 545 | --------------------------------------------------------------------------------