Overview

When working with raster data, you often need to align arbitrary extents to a grid’s cell boundaries. This is essential for:

  • Cropping rasters to a region of interest
  • Mosaicking multiple rasters with consistent alignment
  • Preparing data for analysis that requires aligned grids

The vaster package provides functions to compute these alignments without requiring actual raster data.

The Alignment Problem

Consider a 10x5 grid with 1-unit cells:

dimension <- c(10, 5)
extent <- c(0, 10, 0, 5)

## Cell boundaries are at integers
x_corner(dimension, extent)
#>  [1]  0  1  2  3  4  5  6  7  8  9 10
y_corner(dimension, extent)
#> [1] 0 1 2 3 4 5

If you want to crop to an arbitrary extent like c(2.3, 7.8, 1.2, 4.6), the boundaries don’t align with cell edges. You need to decide how to snap to the nearest cell boundaries.

align_extent()

The align_extent() function snaps an arbitrary extent to align with the grid’s cell boundaries:

user_extent <- c(2.3, 7.8, 1.2, 4.6)

## Snap outward (default) - includes all cells touched
align_extent(user_extent, dimension, extent, snap = "out")
#> [1] 2 8 1 5

## Snap inward - only fully contained cells
align_extent(user_extent, dimension, extent, snap = "in")
#> [1] 3 7 2 4

## Snap to nearest boundary
align_extent(user_extent, dimension, extent, snap = "near")
#> [1] 2 8 1 5

snap_extent()

The snap_extent() function provides a simpler alignment to a fixed resolution, without reference to a specific grid:

## Snap to 0.5 unit resolution
snap_extent(c(2.3, 7.8, 1.2, 4.6), res = 0.5)
#> [1] 2 8 1 5

## Snap to 1 unit resolution
snap_extent(c(2.3, 7.8, 1.2, 4.6), res = 1)
#> [1] 2 8 1 5

This always snaps outward (buffering the extent).

Grid Origin

The origin() function returns the grid’s alignment origin - the point where cell boundaries would intersect if the grid extended infinitely:

## Standard grid has origin at (0, 0)
origin(c(10, 5), c(0, 10, 0, 5))
#> [1] 0 0

## Offset grid
origin(c(10, 5), c(0.5, 10.5, 0.25, 5.25))
#> [1] 0.50 0.25

Two grids with the same resolution and origin will have aligned cells.

vcrop()

The vcrop() function performs a virtual crop operation, returning both the aligned extent and the dimension of the cropped region:

result <- vcrop(c(2.3, 7.8, 1.2, 4.6), dimension, extent)
result$extent
#> [1] 2 8 1 5
result$dimension
#> [1] 6 4

This is useful when you need to know the output dimensions before actually reading data.

intersect_extent()

Find the overlapping region between an extent and a grid:

## Extent that partially overlaps
intersect_extent(c(-2, 5, -1, 3), dimension, extent)
#> [1] -2  5 -1  3

## Extent fully within grid
intersect_extent(c(2, 8, 1, 4), dimension, extent)
#> [1] 2 8 1 4

extent_dimension()

Calculate what dimension a cropped region would have:

crop_extent <- c(2, 8, 1, 4)

## Dimension of the cropped region
extent_dimension(crop_extent, dimension, extent)
#> [1] 6 3

## Verify: 6 columns (8-2) and 3 rows (4-1)

Practical Example: Pre-computing Crop Parameters

A common workflow is to pre-compute crop parameters before reading data:

## Define source grid (e.g., from a large raster file)
src_dim <- c(3600, 1800)  # 0.1 degree global grid
src_ext <- c(-180, 180, -90, 90)

## User's region of interest
roi <- c(140, 155, -45, -30)  # Southeastern Australia

## Align to grid
aligned_roi <- align_extent(roi, src_dim, src_ext, snap = "out")
aligned_roi
#> [1] 140 155 -45 -30

## Get dimensions of cropped region
crop_dim <- extent_dimension(aligned_roi, src_dim, src_ext)
crop_dim
#> [1] 150 150

## Get cell indices to read
cells <- cell_from_extent(src_dim, src_ext, aligned_roi)
length(cells)
#> [1] 22500

## Verify
crop_dim[1] * crop_dim[2]
#> [1] 22500

GDAL Integration

The aligned extent can be converted to GDAL parameters:

## RasterIO parameters for reading the crop region
rio <- rasterio0(src_dim, src_ext, aligned_roi)
rio
#>  offset_x  offset_y source_nx source_ny    out_nx    out_ny      <NA>      <NA> 
#>      3600      1800      -180       180       -90        90       140       155 
#>      <NA>      <NA> 
#>       -45       -30 
#> attr(,"resample")
#> [1] "NearestNeighbour"

This tells GDAL which pixels to read: starting at column/row offset, reading a window of specified size.

Summary

Function Purpose
align_extent() Snap extent to grid boundaries (out/in/near)
snap_extent() Snap extent to resolution (always outward)
origin() Get grid alignment origin
vcrop() Virtual crop: get aligned extent and dimension
intersect_extent() Find overlapping region
extent_dimension() Calculate dimension of aligned extent