#'@title Read NetCDF-CF spatial geometries
#'
#'@param nc_file character file path to the nc file to be read.
#'
#'@description
#'Attempts to convert a NetCDF-CF DSG Simple Geometry file into a sf data.frame.
#'
#'@references
#'http://cfconventions.org/index.html
#'
#'@importFrom RNetCDF open.nc var.get.nc close.nc
#'@importFrom sf st_sf st_sfc st_linestring st_polygon st_multipolygon st_multilinestring st_crs
#'
#'@return sf \code{data.frame} containing spatial geometry of type found in the NetCDF-CF DSG file.
#'
#'@references
#' \enumerate{
#' \item \url{http://cfconventions.org/cf-conventions/cf-conventions.html#_features_and_feature_types}
#' }
#'@export
#'
#'@examples
#'huc_eta_nc <- tempfile()
#'file.copy(system.file('extdata','example_huc_eta.nc', package = 'ncdfgeom'),
#' huc_eta_nc, overwrite = TRUE)
#'
#'vars <- ncmeta::nc_vars(huc_eta_nc)
#'
#'hucPolygons <- sf::read_sf(system.file('extdata','example_huc_eta.json', package = 'ncdfgeom'))
#'plot(sf::st_geometry(hucPolygons))
#'names(hucPolygons)
#'
#'hucPolygons_nc <- ncdfgeom::write_geometry(nc_file=huc_eta_nc,
#' geom_data = hucPolygons,
#' instance_dim_name = "station",
#' variables = vars$name)
#'huc_poly <- read_geometry(huc_eta_nc)
#'plot(sf::st_geometry(huc_poly))
#'names(huc_poly)
#'
read_geometry = function(nc_file) {
nc <- open.nc(nc_file)
on.exit(close.nc(nc), add = TRUE)
nc_props <- check_netcdf(nc)
return(read_geom_data(nc_props, nc))
}
#' @noRd
read_geom_data <- function(nc_props, nc) UseMethod("read_geom_data")
#' @noRd
#' @name read_geom_data
read_geom_data.point <- function(nc_props, nc) {
coord <- get_coords(nc, nc_props)
prj <- get_prj_nc(nc_props)
point_data <- data.frame(x = coord$x, y = coord$y)
data_frame <- read_attribute_data(nc, nc_props$instance_dim)
if(nrow(data_frame) != nrow(point_data)) {
stop("Reading multipoint is not supported yet.")
# This is where handling for multipoint would go.
}
return(st_as_sf(cbind(point_data, data_frame), crs = st_crs(prj), coords = c("x", "y")))
}
#' @noRd
#' @name read_geom_data
read_geom_data.line <- function(nc_props, nc) {
return(parse_geom(nc_props, nc))
}
#' @noRd
#' @name read_geom_data
read_geom_data.polygon <- function(nc_props, nc) {
return(parse_geom(nc_props, nc))
}
get_coords <- function(nc, nc_props) {
list(x = c(var.get.nc(nc, nc_props$geom_container$x)),
y = c(var.get.nc(nc, nc_props$geom_container$y)))
}
get_prj_nc <- function(nc_props) {
if(length(nc_props$crs) == 0) {
warning("no crs found, using WGS84")
prj <- "+proj=longlat +datum=WGS84"
} else {
prj <- ncmeta::nc_gm_to_prj(nc_props$crs)
}
}
populate_nc_props <- function(nc_props, nc) {
nc_props$geom_container$node_count <- c(var.get.nc(nc, nc_props$geom_container$node_count))
if(length(nc_props$geom_container$part_node_count) > 0) {
nc_props$geom_container$part_node_count <- var.get.nc(nc, nc_props$geom_container$part_node_count)
} else {
nc_props$geom_container$part_node_count <- nc_props$geom_container$node_count
}
if(length(nc_props$geom_container$part_type) > 0) {
nc_props$geom_container$part_type <- var.get.nc(nc, nc_props$geom_container$part_type)
} else {
nc_props$geom_container$part_type <- rep(pkg.env$multi_val, length(nc_props$geom_container$part_node_count))
}
return(nc_props)
}
parse_geom <- function(nc_props, nc) {
coord <- get_coords(nc, nc_props)
prj <- get_prj_nc(nc_props)
nc_props <- populate_nc_props(nc_props, nc)
poly <- class(nc_props) == "polygon"
node_start <- 1
geom_node_stop <- 0
p_ind <- 1
f_list <- list()
multi_geometry <- FALSE
for(geom in 1:length(nc_props$geom_container$node_count)) {
multi_g <- FALSE
geom_node_stop <- geom_node_stop + nc_props$geom_container$node_count[geom]
p_list <- list()
p <- 0
while(node_start < geom_node_stop) {
p <- p + 1
part_node_stop <- node_start + nc_props$geom_container$part_node_count[p_ind] - 1
coords <- list(matrix(c(coord$x[node_start:part_node_stop],
coord$y[node_start:part_node_stop]),
ncol = 2))
dimnames(coords[[1]]) <- list(NULL, c(pkg.env$x_nodes, pkg.env$y_nodes))
# Assume not multi to start
if(nc_props$geom_container$part_type[p_ind] == pkg.env$hole_val) {
p <- p - 1
p_list[[p]] <- append(p_list[[p]], coords)
} else {
if(p == 2) {
multi_g <- TRUE
p_list <- append(p_list, list(coords))
} else if(p > 2) {
p_list <- append(p_list, list(coords))
} else {
p_list <- append(p_list, list(coords))
}
}
node_start <- node_start + nc_props$geom_container$part_node_count[p_ind]
p_ind <- p_ind + 1
}
if(multi_g) {
multi_geometry <- TRUE
if(poly) {
f_list <- append(f_list, list(st_multipolygon(p_list)))
} else {
if(p_ind > 1) {
p_list <- unlist(p_list, recursive = FALSE)
f_list <- append(f_list, list(st_multilinestring(p_list)))
} else {
f_list <- append(f_list, list(st_linestring(p_list)))
}
}
} else {
p_list <- unlist(p_list, recursive = FALSE)
if(poly) {
f_list <- append(f_list, list(st_polygon(p_list)))
} else {
f_list <- append(f_list, list(st_linestring(p_list[[1]])))
}
}
}
df <- read_attribute_data(nc, nc_props$instance_dim)
for(var_name in names(df)) {
if(!var_name %in% nc_props$variable_list) {
df[var_name] <- NULL
}
}
if(!poly) cast_to <- "LINESTRING"
if(!poly & multi_geometry) cast_to <- "MULTILINESTRING"
if(poly) cast_to <- "POLYGON"
if(poly & multi_geometry) cast_to <- "MULTIPOLYGON"
return(st_sf(geom = sf::st_cast(st_sfc(f_list, crs = st_crs(prj)), cast_to),
check_ring_dir = poly, df,
agr = "constant",
sfc_last = TRUE))
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.