% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/ddbs_measure.R
\name{ddbs_measure_funs}
\alias{ddbs_measure_funs}
\alias{ddbs_area}
\alias{ddbs_length}
\alias{ddbs_perimeter}
\alias{ddbs_distance}
\alias{ddbs_azimuth}
\title{Calculate geometric measurements}
\usage{
ddbs_area(
  x,
  new_column = "area",
  conn = NULL,
  name = NULL,
  mode = NULL,
  overwrite = FALSE,
  quiet = FALSE
)

ddbs_length(
  x,
  new_column = "length",
  conn = NULL,
  name = NULL,
  mode = NULL,
  overwrite = FALSE,
  quiet = FALSE
)

ddbs_perimeter(
  x,
  new_column = "perimeter",
  conn = NULL,
  name = NULL,
  mode = NULL,
  overwrite = FALSE,
  quiet = FALSE
)

ddbs_distance(
  x,
  y,
  dist_type = NULL,
  conn = NULL,
  conn_x = NULL,
  conn_y = NULL,
  id_x = NULL,
  id_y = NULL,
  name = NULL,
  mode = NULL,
  overwrite = FALSE,
  quiet = FALSE
)

ddbs_azimuth(
  x,
  y,
  unit = "radians",
  conn = NULL,
  conn_x = NULL,
  conn_y = NULL,
  id_x = NULL,
  id_y = NULL,
  name = NULL,
  mode = NULL,
  overwrite = FALSE,
  quiet = FALSE
)
}
\arguments{
\item{x}{Input geometry (sf object, duckspatial_df, or table name in DuckDB)}

\item{new_column}{Name of the new column to create on the input data. Ignored
with \code{mode = "sf"}.}

\item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function
runs on a temporary DuckDB database.}

\item{name}{A character string of length one specifying the name of the table,
or a character string of length two specifying the schema and table
names. If \code{NULL} (the default), the function returns the result as an
\code{sf} object}

\item{mode}{Character. Controls the return type. Options:
\itemize{
\item \code{"duckspatial"} (default): Lazy spatial data frame backed by dbplyr/DuckDB
\item \code{"sf"}: Eagerly collected sf object (uses memory)
}
Can be set globally via \code{\link{ddbs_options}(mode = "...")} or
per-function via this argument. Per-function overrides global setting.}

\item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults
to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.}

\item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages.
Defaults to \code{FALSE}.}

\item{y}{Second input geometry for distance and azimuth calculations (sf object, duckspatial_df, or table name)}

\item{dist_type}{Character. Distance type to be calculated. By default it uses
the best option for the input CRS (see details).}

\item{conn_x}{A \code{DBIConnection} object to a DuckDB database for the input \code{x}.
If \code{NULL} (default), it is resolved from \code{conn} or extracted from \code{x}.}

\item{conn_y}{A \code{DBIConnection} object to a DuckDB database for the input \code{y}.
If \code{NULL} (default), it is resolved from \code{conn} or extracted from \code{y}.}

\item{id_x}{Character; optional name of the column in \code{x} whose values will
be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.}

\item{id_y}{Character; optional name of the column in \code{y} whose values will
replace the integer indices returned in each element of the list.}

\item{unit}{Character. Output unit: \code{"radians"} (default) or \code{"degrees"}.}
}
\value{
For \code{ddbs_area}, \code{ddbs_length}, and \code{ddbs_perimeter}:
\itemize{
\item \code{mode = "duckspatial"} (default): A \code{duckspatial_df} (lazy spatial data frame) backed by dbplyr/DuckDB.
\item \code{mode = "sf"}: An eagerly collected vector in R memory.
\item When \code{name} is provided: writes the table in the DuckDB connection and returns \code{TRUE} (invisibly).
}

For \code{ddbs_distance}: A \code{units} matrix in meters with dimensions nrow(x), nrow(y).

For \code{ddbs_azimuth}: A numeric matrix of azimuth values (in the specified \code{unit})
with dimensions nrow(x) by nrow(y) when \code{mode = "sf"}, or a lazy
\code{tbl_duckdb_connection} with columns \code{id_x}, \code{id_y}, and \code{azimuth} otherwise.
Both inputs must contain only POINT geometries.
}
\description{
Compute area, length, perimeter, or distance of geometries with automatic
method selection based on the coordinate reference system (CRS).
}
\details{
These functions automatically select the appropriate calculation method based on the input CRS:

\strong{For EPSG:4326 (geographic coordinates):}
\itemize{
\item Uses \code{ST_*_Spheroid} functions (e.g., \code{ST_Area_Spheroid}, \code{ST_Length_Spheroid})
\item Leverages GeographicLib library for ellipsoidal earth model calculations
\item Highly accurate but slower than planar calculations
\item For \code{ddbs_distance} with POINT geometries: defaults to \code{"haversine"}
\item For \code{ddbs_distance} with other geometries: defaults to \code{"spheroid"}
}

\strong{For projected CRS (e.g., UTM, Web Mercator):}
\itemize{
\item Uses planar \code{ST_*} functions (e.g., \code{ST_Area}, \code{ST_Length})
\item Faster performance with accurate results in meters
\item For \code{ddbs_distance}: defaults to \code{"planar"}
}

\strong{Distance calculation methods} (\code{dist_type} argument):
\itemize{
\item \code{NULL} (default): Automatically selects best method for input CRS
\item \code{"planar"}: Planar distance (for projected CRS)
\item \code{"geos"}: Planar distance using GEOS library (for projected CRS)
\item \code{"haversine"}: Great circle distance (requires EPSG:4326 and POINT geometries)
\item \code{"spheroid"}: Ellipsoidal model using GeographicLib (most accurate, slowest)
}

\strong{Distance type requirements:}
\itemize{
\item \code{"planar"} and \code{"geos"}: Require projected coordinates (not degrees)
\item \code{"haversine"} and \code{"spheroid"}: Require POINT geometries and EPSG:4326
}
}
\section{Performance}{

Speed comparison (fastest to slowest):
\enumerate{
\item Planar calculations on projected CRS
\item Haversine (spherical approximation)
\item Spheroid functions (ellipsoidal model)
}
}

\examples{
\dontrun{
library(duckspatial)
library(dplyr)

# Create a DuckDB connection
conn <- ddbs_create_conn(dbdir = "memory")

# ===== AREA CALCULATIONS =====

# Load polygon data
countries_ddbs <- ddbs_open_dataset(
  system.file("spatial/countries.geojson", package = "duckspatial")
) |>
  ddbs_transform("EPSG:3857") |> 
  filter(NAME_ENGL != "Antarctica")

# Store in DuckDB
ddbs_write_table(conn, countries_ddbs, "countries")

# Calculate area (adds a new column - area by default)
ddbs_area("countries", conn)

# Calculate area with custom column name
ddbs_area("countries", conn, new_column = "area_sqm")

# Create new table with area calculations
ddbs_area("countries", conn, name = "countries_with_area", new_column = "area_sqm")

# Calculate area from sf object directly
ddbs_area(countries_ddbs)

# Calculate area using dplyr syntax
countries_ddbs |> 
  mutate(area = ddbs_area(geom))

# Calculate total area 
countries_ddbs |> 
  mutate(area = ddbs_area(geom)) |> 
  summarise(
    area = sum(area),
    geom = ddbs_union(geom)
  )

# ===== LENGTH CALCULATIONS =====

# Load line data
rivers_ddbs <- sf::read_sf(
  system.file("spatial/rivers.geojson", package = "duckspatial")
) |> 
  as_duckspatial_df()

# Store in DuckDB
ddbs_write_table(conn, rivers_ddbs, "rivers")

# Calculate length (add a new column - length by default)
ddbs_length("rivers", conn)

# Calculate length with custom column name
ddbs_length(rivers_ddbs, new_column = "length_meters")

# Calculate length by river name
rivers_ddbs |> 
  ddbs_union_agg("RIVER_NAME") |> 
  ddbs_length()

# Add length within dplyr
rivers_ddbs |> 
  mutate(length = ddbs_length(geometry))


# ===== PERIMETER CALCULATIONS =====

# Calculate perimeter (returns sf object with perimeter column)
ddbs_perimeter(countries_ddbs)

# Calculate perimeter within dplyr
countries_ddbs |> 
  mutate(perim = ddbs_perimeter(geom))


# ===== DISTANCE CALCULATIONS =====

# Create sample points in EPSG:4326
n <- 10
points_sf <- data.frame(
  id = 1:n,
  x = runif(n, min = -180, max = 180),
  y = runif(n, min = -90, max = 90)
) |>
  ddbs_as_spatial(coords = c("x", "y"), crs = "EPSG:4326")

# Option 1: Using sf objects (auto-selects haversine for EPSG:4326 points)
dist_matrix <- ddbs_distance(x = points_sf, y = points_sf)
head(dist_matrix)

# Option 2: Explicitly specify distance type
dist_matrix_harv <- ddbs_distance(
  x = points_sf,
  y = points_sf,
  dist_type = "haversine"
)

# Option 3: Using DuckDB tables
ddbs_write_table(conn, points_sf, "points", overwrite = TRUE)
dist_matrix_sph <- ddbs_distance(
  conn = conn,
  x = "points",
  y = "points",
  dist_type = "spheroid"  # Most accurate for geographic coordinates
)
head(dist_matrix_sph)

# Close connection
ddbs_stop_conn(conn)
}
\dontrun{
library(duckspatial)

# Create two sets of points in a projected CRS
origins <- sf::st_as_sf(
  data.frame(id = 1:2, x = c(0, 0), y = c(0, 0)),
  coords = c("x", "y"), crs = "EPSG:3857"
)
destinations <- sf::st_as_sf(
  data.frame(id = 1:2, x = c(0, 1), y = c(1, 0)),
  coords = c("x", "y"), crs = "EPSG:3857"
)

# Returns a numeric matrix (nrow(origins) x nrow(destinations))
ddbs_azimuth(origins, destinations, mode = "sf")

# In degrees
ddbs_azimuth(origins, destinations, unit = "degrees", mode = "sf")

# Lazy tbl with all pairs (default mode)
ddbs_azimuth(origins, destinations)
}
}
\references{
\url{https://geographiclib.sourceforge.io/}
}
