--- title: "Cell Operations" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Cell Operations} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(vaster) ``` ## Overview Cell operations are at the heart of raster grid logic. This vignette covers: - Converting between **cell indices** and **x,y coordinates** - Converting between **cell indices** and **row/column positions** - Working with **extents** from cells - Finding cells within an **extent** All functions use the standard vaster convention: `dimension` is `c(ncol, nrow)` and `extent` is `c(xmin, xmax, ymin, ymax)`. ## Cell Indexing Cells are numbered starting from 1 at the **top-left** corner, proceeding **row-wise** (left-to-right, then top-to-bottom): ``` 1 2 3 4 5 6 7 8 9 10 11 12 ``` ```{r} ## define a simple 4x3 grid dimension <- c(4, 3) # 4 columns, 3 rows extent <- c(0, 4, 0, 3) # xmin=0, xmax=4, ymin=0, ymax=3 n_cell(dimension) n_col(dimension) n_row(dimension) ``` ## Cells ↔ Coordinates ### From cells to coordinates Use `xy_from_cell()` to get the **centre coordinates** of cells: ```{r} ## single cell xy_from_cell(dimension, extent, 1) ## multiple cells xy_from_cell(dimension, extent, c(1, 4, 9, 12)) ## all cells xy_from_cell(dimension, extent, seq_len(n_cell(dimension))) ``` For just x or y coordinates: ```{r} x_from_cell(dimension, extent, 1:4) y_from_cell(dimension, extent, c(1, 5, 9)) ``` ### From coordinates to cells Use `cell_from_xy()` to find which cell contains given coordinates: ```{r} ## coordinates at cell centres xy <- cbind(c(0.5, 1.5, 2.5), c(2.5, 1.5, 0.5)) cell_from_xy(dimension, extent, xy) ## coordinates outside the grid return NA xy_outside <- cbind(c(-1, 5), c(1.5, 1.5)) cell_from_xy(dimension, extent, xy_outside) ## coordinates on cell boundaries go to the cell below/right ## except at the grid edge where they go to the last cell xy_edge <- cbind(c(1.0, 4.0), c(2.0, 0.0)) cell_from_xy(dimension, extent, xy_edge) ``` ## Cells ↔ Row/Column ### From cells to row/column ```{r} ## get row and column for cells rowcol_from_cell(dimension, extent, 1:12) ``` For just row or column: ```{r} row_from_cell(dimension, 1:12) col_from_cell(dimension, 1:12) ``` Note that `row_from_cell()` and `col_from_cell()` only need `dimension` since row/column positions don't depend on extent. ### From row/column to cells Get cells for specific row/column combinations: ```{r} ## single cell at row 2, column 3 cell_from_row_col(dimension, row = 2, col = 3) ## multiple cells (vectorized, with recycling) cell_from_row_col(dimension, row = 1:3, col = 1:3) # diagonal cells ``` Get **all cells** in specific rows or columns: ```{r} ## all cells in row 2 cell_from_row(dimension, 2) ## all cells in column 3 cell_from_col(dimension, 3) ``` Get the **cross-product** of rows and columns (all combinations): ```{r} ## all cells in rows 1-2 AND columns 2-3 cell_from_rowcol_combine(dimension, row = 1:2, col = 2:3) ``` ## Rows/Columns ↔ Coordinates Convert directly between row/column indices and coordinates: ```{r} ## x coordinate of each column (centre) x_from_col(dimension, extent, 1:4) ## y coordinate of each row (centre) y_from_row(dimension, extent, 1:3) ## which column contains this x coordinate col_from_x(dimension, extent, c(0.5, 2.5, 3.9)) ## which row contains this y coordinate row_from_y(dimension, extent, c(2.5, 1.5, 0.1)) ``` ## Cells ↔ Extents ### Extent from cells Get the bounding box that covers a set of cells: ```{r} ## extent of a single cell extent_from_cell(dimension, extent, 1) ## extent covering multiple cells extent_from_cell(dimension, extent, c(1, 4)) # top row extent_from_cell(dimension, extent, c(1, 12)) # full grid ``` ### Cells from extent Find all cells within a given extent: ```{r} ## cells within a sub-extent sub_extent <- c(1, 3, 1, 2) # xmin=1, xmax=3, ymin=1, ymax=2 cell_from_extent(dimension, extent, sub_extent) ``` The extent is automatically aligned to cell boundaries before finding cells. ## Handling Invalid Inputs Functions return `NA` for invalid inputs: ```{r} ## invalid cell numbers xy_from_cell(dimension, extent, c(0, 13, -1)) ## coordinates outside grid cell_from_xy(dimension, extent, cbind(c(-1, 10), c(1, 1))) ## invalid row/column cell_from_row_col(dimension, row = 0, col = 1) cell_from_row_col(dimension, row = 4, col = 1) # only 3 rows exist ``` ## Practical Example: Sampling Grid Points Create a stratified sample by selecting one random point from each cell: ```{r} set.seed(42) dimension <- c(5, 4) extent <- c(0, 10, 0, 8) ## get cell centres centres <- xy_from_cell(dimension, extent, seq_len(n_cell(dimension))) ## add random jitter within each cell res <- c(x_res(dimension, extent), y_res(dimension, extent)) jitter_x <- runif(n_cell(dimension), -res[1]/2, res[1]/2) jitter_y <- runif(n_cell(dimension), -res[2]/2, res[2]/2) sample_points <- cbind( x = centres[, 1] + jitter_x, y = centres[, 2] + jitter_y ) head(sample_points) ## verify all points fall in expected cells all(cell_from_xy(dimension, extent, sample_points) == seq_len(n_cell(dimension))) ``` ## See Also - `vignette("grid-fundamentals")`: Basic grid concepts - `vignette("extent-alignment")`: Aligning extents to grids - `vignette("gdal-interop")`: GDAL geotransform operations