1
#' HERE Geocoder API: Reverse Geocode
2
#'
3
#' Get addresses from locations using the HERE 'Geocoder' API.
4
#' The return value is an \code{sf} object, containing point geometries
5
#' with suggestions for addresses near the provided POIs.
6
#'
7
#' @references
8
#' \href{https://developer.here.com/documentation/geocoding-search-api/dev_guide/topics/endpoint-reverse-geocode-brief.html}{HERE Geocoder API: Reverse Geocode}
9
#'
10
#' @param poi \code{sf} object, Points of Interest (POIs) of geometry type \code{POINT}.
11
#' @param results numeric, maximum number of results (Valid range: 1 and 100).
12
#' @param sf boolean, return an \code{sf} object (\code{default = TRUE}) or a
13
#'   \code{data.frame}?
14
#' @param url_only boolean, only return the generated URLs (\code{default = FALSE})?
15
#'
16
#' @return
17
#' If \code{sf = TRUE}, an \code{sf} object, containing the position coordinates
18
#' of the reverse geocoded POIs as geometry list column and the access
19
#' coordinates as well-known text (WKT).
20
#' If \code{sf = FALSE}, a \code{data.frame} containing the
21
#' coordinates of the reverse geocoded POIs as \code{lng}, \code{lat} columns.
22
#' @export
23
#'
24
#' @note If no addresses are found near a POI, \code{NULL} for this POI is returned.
25
#' In this case the rows corresponding to this particular POI are missing and merging the POIs by row is not possible.
26
#' However, in the returned \code{sf} object, the column \code{"id"} matches the rows of the input POIs.
27
#' The \code{"id"} column can be used to join the original POIs.
28
#'
29
#' @examples
30
#' # Provide an API Key for a HERE project
31
#' set_key("<YOUR API KEY>")
32
#'
33
#' # Get addresses
34
#' addresses <- reverse_geocode(poi = poi, results = 3, url_only = TRUE)
35
reverse_geocode <- function(poi, results = 1, sf = TRUE, url_only = FALSE) {
36

37
  # Input checks
38 1
  .check_points(poi)
39 1
  .check_numeric_range(results, 1, 100)
40 1
  .check_boolean(sf)
41 1
  .check_boolean(url_only)
42

43
  # Add API key
44 1
  url <- .add_key(
45 1
    url = "https://revgeocode.search.hereapi.com/v1/revgeocode?"
46
  )
47

48
  # Add point coords
49 1
  coords <- sf::st_coordinates(
50 1
    sf::st_transform(poi, 4326)
51
  )
52 1
  url = paste0(
53 1
    url,
54 1
    "&at=", coords[, 2], ",", coords[, 1]
55
  )
56

57
  # Add language
58 1
  url = paste0(
59 1
    url,
60 1
    "&lang=en-US"
61
  )
62

63
  # Add max results
64 1
  url = paste0(
65 1
    url,
66 1
    "&limit=",
67 1
    results
68
  )
69

70
  # Return urls if chosen
71 0
  if (url_only) return(url)
72

73
  # Request and get content
74 1
  data <- .get_content(
75 1
    url = url
76
  )
77 0
  if (length(data) == 0) return(NULL)
78

79
  # Extract information
80 1
  reverse <- .extract_addresses(data)
81

82
  # Create sf object
83 1
  if (nrow(reverse) > 0) {
84 1
    rownames(reverse) <- NULL
85
    # Return sf object if chosen
86 1
    if (sf) {
87
      # Parse access coordinates to WKT
88 1
      reverse$access <- .wkt_from_point_df(reverse, "lng_access", "lat_access")
89 1
      reverse[, c("lng_access", "lat_access") := NULL]
90
      # Parse position coordinates and set as default geometry
91 1
      return(
92 1
        sf::st_set_crs(
93 1
          sf::st_as_sf(
94 1
            as.data.frame(reverse),
95 1
            coords = c("lng_position", "lat_position"),
96 1
            sf_column_name = "geometry"
97 1
          ), value = 4326
98
        )
99
      )
100
    } else {
101 1
      return(as.data.frame(reverse))
102
    }
103
  } else {
104 0
    return(NULL)
105
  }
106
}
107

108
.extract_addresses <- function(data) {
109 1
    template <- data.table::data.table(
110 1
    id = numeric(),
111 1
    rank = numeric(),
112 1
    address = character(),
113 1
    type = character(),
114 1
    street = character(),
115 1
    house_number = character(),
116 1
    postal_code = character(),
117 1
    district = character(),
118 1
    city = character(),
119 1
    county = character(),
120 1
    state = character(),
121 1
    country = character(),
122 1
    distance = numeric(),
123 1
    lng_access = numeric(),
124 1
    lat_access = numeric(),
125 1
    lng_position = numeric(),
126 1
    lat_position = numeric()
127
  )
128 1
  ids <- .get_ids(data)
129 1
  count <- 0
130 1
  result <- data.table::rbindlist(
131 1
    append(list(template),
132 1
      lapply(data, function(con) {
133 1
        count <<- count + 1
134 1
        df <- jsonlite::fromJSON(con)
135 0
        if (length(nrow(df$items)) == 0) return(NULL)
136 1
        data.table::data.table(
137 1
          id = ids[count],
138 1
          rank = seq(1, nrow(df$items)),
139 1
          address = df$items$title,
140 1
          type = df$items$resultType,
141 1
          street = df$items$address$street,
142 1
          house_number = df$items$address$houseNumber,
143 1
          postal_code = df$items$address$postalCode,
144 1
          district = df$items$address$district,
145 1
          city = df$items$address$city,
146 1
          county = df$items$address$county,
147 1
          state = df$items$address$state,
148 1
          country = df$items$address$countryName,
149 1
          distance = df$items$distance,
150 1
          lng_access = if (is.null(df$items$access[[1]]$lng)) NA else df$items$access[[1]]$lng,
151 1
          lat_access = if (is.null(df$items$access[[1]]$lat)) NA else df$items$access[[1]]$lat,
152 1
          lng_position = df$items$position$lng,
153 1
          lat_position = df$items$position$lat
154
        )
155
      })
156 1
    ), fill = TRUE)
157 1
  result
158
}

Read our documentation on viewing source code .

Loading