---
title: "From a QuadKey to a Simple Features data.frame and other conversions"
author: "Florencia D'Andrea"
date: "`r Sys.Date()`"
output:
html_document:
toc : true
number_sections: true
toc_depth: 3
urlcolor: blue
pkgdown:
as_is: true
vignette: >
%\VignetteIndexEntry{From a QuadKey to a Simple Features data.frame and other conversions}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>"
)
```
```{r setup, echo = FALSE, message=FALSE, warning=FALSE}
library(quadkeyr)
library(ggplot2)
```
> Please, visit the [README](https://docs.ropensci.org/quadkeyr/)
> for general information about this package
`quadkeyr` functions are the R version of the ones described
in the documentation at [Bing Maps Tile System webpage](https://learn.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system).
Most of the function and arguments names are preserved from the documentation,
if not it will be indicated in the text.
# Basic workflow
```{r w1, echo = FALSE, out.width= "80%", fig.align='center'}
knitr::include_graphics("workflow_quadkey.png")
```
You can convert any QuadKey to
a [Simple Features object](https://r-spatial.github.io/sf/articles/sf1.html#sf-objects-with-simple-features)
`sf` POINT data.frame or `sf` POLYGON data.frame
using the functions `quadkey_to_latlong()` and `quadkey_to_polygon()`.
It's important to notice that the geographic coordinates of the point
will always correspond to the upper-left corner of the polygon
for the same QuadKey.
```{r}
qtll <- quadkey_to_latlong(quadkey = "2103")
qtll
```
```{r}
qtp <- quadkey_to_polygon(quadkey = "2103")
qtp
```
```{r qk, out.width="50%", fig.align='center'}
ggplot() +
geom_sf(data = qtp, color = 'red', fill = NA, linewidth = 2.5) +
geom_sf(data = qtll, color = 'blue', size = 4) +
ggtitle(paste("QuadKey", qtll$quadkey)) +
theme_minimal()
```
If you want to convert a data.frame with a `quadkey` column
into a `sf` POLYGON data.frame.
you can use the function `quadkey_df_to_polygon()`
described in the
[`Generating a Raster Image from Quadkey-Identified Data` vignette](https://docs.ropensci.org/quadkeyr/articles/quadkey_identified_data_to_raster.html)
# Advanced use: intermediate functions
The conversion from QuadKey to geographic coordinates
involves a series of smaller transformations that
relate to the structure of Tile Maps.
All of these intermediary functions,
as well as those facilitating the reverse conversion
from geographic coordinates to QuadKey,
are available for use within the `quadkeyr` package.
## Tile Maps: QuadKeys, tiles, pixels and geographic coordinates
> Note: In the official documentation,
> the term 'level of detail' is equivalent to
> what is here referred to as 'zoom level'.
Tile maps are composed of pixels that are grouped into tiles.
Later, the tiles are converted to QuadKeys to optimize map performance,
among other benefits described in detail in
[the documentation](https://learn.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system).
Pixels and tiles are expressed as two-dimensional coordinates
- (`pixelX`, `pixelY`) and (`tileX`, `tileY`) -
but QuadKeys are one-dimensional numeric strings.
This difference is important to understand how the conversion works.
Each geographic pair of coordinates (latitude/longitude)
will belong to a specific pixel
referenced by coordinates (`pixelX`, `pixelY`)
for each zoom level.
In Fig. 1, you can see pixels (0, 0) and (2047, 2047)
for zoom level 3.
The `quadkeyr` function `latlong_to_pixelXY()`,
converts geographic coordinates (latitude/longitude)
in pixel coordinates for each zoom level.
```{r pixels, echo = FALSE, out.width= "50%", fig.align='center', fig.cap= "Fig 1. Pixels (0, 0) and (2047, 2047) for a map with zoom level 3. Image extracted from Microsoft's Bing Maps Tile System webpage."}
knitr::include_graphics('bing_pixel.jpg')
```
In turn, a tile is comprised of 256x256 pixels.
The tile coordinates are visually represented in Fig. 2.
These coordinates will ultimately be converted
into one-dimensional QuadKeys.
For instance, a pixel for zoom level 3 represented by
the coordinates `pixelX` = 255 and
`pixelY` = 12 is part of the tile with
coordinates `tileX` = 0 and `tileY` = 0.
The pixel with coordinates (0,0) belongs to tile (0,0), and the
pixel (2047, 2047) is part of tile (7,7).
You can verify this using
the function `pixelXY_to_tileXY()` and
by comparing Fig. 1 and Fig. 2.
```{r tiles, echo = FALSE, out.width= "50%", fig.align='center', fig.cap= "Fig 2. Tile coordinates. Image extracted from Microsoft's Bing Maps Tile System webpage."}
knitr::include_graphics('bing_tiles.jpg')
```
To convert from tile XY coordinates to QuadKeys
for a particular zoom level,
you can use the function `tileXY_to_quadkey()`.
The number of digits of the QuadKey
will correspond to the zoom level
of the map. For example,
for the tile (4, 7) of zoom level 3, the
QuadKey will be `322`.
This pertains to the conversion from
geographic coordinates (latitude/longitude) to QuadKeys.
However, when converting in the opposite direction,
from QuadKeys to geographic coordinates,
the latitude/longitude obtained correspond to
the upper-left corner coordinates
of the tile and pixel associated with
your original QuadKey.
To understand this in more detail,
have a look to the functions and then read section 3.
## If you have geographic map coordinates, convert them to QuadKeys
**Geographic coordinates** → **pixel XY coordinates**
→ **tile XY coordinates** → **QuadKey**
> Note:
> The latitude and longitude coordinates are in the WGS 84 reference system.
### Convert latitude/longitude coordinates to pixel XY coordinates
```{r lltp}
lltp <- latlong_to_pixelXY(lat = -25,
lon = -53,
zoom = 4)
lltp
```
### Convert pixel XY coordinates into tile XY coordinates
```{r ptt}
ptt <- pixelXY_to_tileXY(pixelX = lltp$pixelX,
pixelY = lltp$pixelY)
ptt
```
### Convert tile XY coordinates into a QuadKey
This function returns the QuadKey string.
Since we are estimating zoom level 4,
the QuadKey has 4 digits.
```{r ttq}
tileXY_to_quadkey(tileX = ptt$tileX,
tileY = ptt$tileY,
zoom = 4)
```
### Direct conversion from geographic coordinates to one or more QuadKeys
```{r lltqd, echo = FALSE, out.width= "60%", fig.align='center'}
knitr::include_graphics("latlong_to_qk.png")
```
The function `latlong_to_quadkey()`
wraps the last three functions,
and converts map coordinates into a QuadKey
for a particular zoom level:
```{r}
latlong_to_quadkey(lat = -25,
lon = -53,
zoom = 4)
```
This function also work for multiple coordinates:
```{r}
latlong_to_quadkey(lat = c(-4, -25.33, -25.66),
lon = c(-53, -60.33, -70.66),
zoom = 4)
```
## If you have QuadKeys, convert them to map coordinates
Let's attempt the reverse route.
**QuadKey** → **tile XY coordinates** →
**pixel XY coordinates** → **Geographic coordinates**
### Convert a QuadKey into tile XY coordinates
```{r qtt}
qtt <- quadkey_to_tileXY("2103")
qtt
```
### Convert tile XY coordinates into pixel XY coordinates
```{r ttp}
ttp <- tileXY_to_pixelXY(tileX = qtt$tileX,
tileY = qtt$tileY)
ttp
```
### Convert pixel XY coordinates into lat/long coordinates
```{r ptll}
ptll <- pixelXY_to_latlong(pixelX = ttp$pixelX,
pixelY = ttp$pixelY,
zoom = 4)
ptll
```
### Direct conversion from one or more QuadKeys to geographic coordinates
```{r qtlld, echo = FALSE, out.width= "60%", fig.align='center'}
knitr::include_graphics("qk_to_latlong.png")
```
You can also use the function `quadkey_to_latlong()`
that wraps the last three functions and returns a `sf` POINT data.frame.
```{r ex1}
quadkey_to_latlong(quadkey_data = "2103")
```
```{r ex2}
quadkey_to_latlong(quadkey_data = c("213", "212", "210"))
```
# Caveats when converting coordinates
Given the process of converting
geographic coordinates (latitude/longitude) to QuadKeys,
one might expect that the conversion back to
latitude/longitude coordinates (as in section 2.3)
would yield the same values as the original input in section 1.
However, this isn't the case, as evidenced by the results of the
functions `pixelXY_to_tileXY()` and `tileXY_to_pixel_XY()`.
When choosing latitude/longitude coordinates
in the initial function in section 1,
they were within a specific pixel represented by
unique tile coordinates and QuadKey.
As you can see in the example in this vignette,
the conversion back from QuadKey to latitude/longitude
does not directly result in the same initial geographic coordinates.
This discrepancy arises because `tileXY_to_pixel_XY()`
provides the pixel coordinates for the upper-left corner of the tile,
not the exact coordinates chosen initially.
For example, if you run `tileXY_to_pixelXY()` for
the tile XY coordinates are (7, 7),
the resulting pixel XY coordinates are (1792, 1792) and
no (2047, 2047) as you could see in Fig. 2.
As each tile is 256x256 pixels,
you can easily check that the result is the upper-left pixel
of that tile. The same will happen for `pixelXY_to_latlong()`.
Hence, converting latitude/longitude coordinates into a QuadKey
and then back to latitude/longitude won't yield identical values,
unless the initial latitude/longitude coordinates correspond to
the upper-left to the upper-left Quadkey's pixel and tile XY coordinates
at the same zool level.
Consider as initial values the coordinates result of
the conversion from QuadKey to latitude/longitude
obtained in section 2.3 `(lat = -21.94305, lon = -67.5)`
and rerun all functions from the beginning.
You'll proof this way that obtaining the original geographic coordinates
is unlikely unless the initial coordinates correspond
to the upper-left upper-left Quadkey's pixel and tile XY coordinates.
Understanding this distinction is crucial for
the accurate use of these functions in coordinate conversions.
### Additional functions
In addition to the conversion functions mentioned earlier,
the `quadkeyr` package also includes the following functions:
`mapsize()`, `mapscale()`, and `ground_res()`.
These functions are described on the
[Bing Maps Tile System webpage](https://learn.microsoft.com/en-us/bingmaps/articles/bing-maps-tile-system)
and are available for its use.
# QuadKey map visualizer app
You can visualize the QuadKey location in the map
using the Shiny app included in this package.
```{r eval = FALSE}
qkmap_app()
```
```{r qkmap_qk, echo = FALSE, out.width= "70%", fig.align='center'}
knitr::include_graphics("qkmap_qk.png")
```