diff --git a/R/gml.R b/R/gml.R index 7d370ab61cd4cbc59d73111466ab2327255fa762..eb0bd5a1904a15edfb283150d6b1fe2e34d1faf4 100644 --- a/R/gml.R +++ b/R/gml.R @@ -1,6 +1,5 @@ -#============================== GML CLASSES AND METHODS ================================ -#============================== GML ================================ +#===== r2ogs6_gml ===== #'r2ogs6_gml @@ -10,23 +9,31 @@ #'@param polylines Optional: A list of polylines #'@param surfaces Optional: A list of surfaces #'@export -r2ogs6_gml <- function(name, points, polylines = NULL, surfaces = NULL){ +r2ogs6_gml <- function(name, + points, + polylines = NULL, + surfaces = NULL){ #Make this more user friendly #... - validate_r2ogs6_gml(new_r2ogs6_gml(name, points, polylines, surfaces)) + validate_r2ogs6_gml(new_r2ogs6_gml(name, + points, + polylines, + surfaces)) } - #'new_r2ogs6_gml #'@description Constructor for S3 class new_r2ogs6_gml #'@param name The name of the geometry #'@param points A tibble of points #'@param polylines Optional: A list of polylines #'@param surfaces Optional: A list of surfaces -new_r2ogs6_gml <- function(name, points, polylines = NULL, surfaces = NULL) { +new_r2ogs6_gml <- function(name, + points, + polylines = NULL, + surfaces = NULL) { assertthat::assert_that(assertthat::is.string(name)) @@ -44,17 +51,200 @@ new_r2ogs6_gml <- function(name, points, polylines = NULL, surfaces = NULL) { list(name = name, points = points, polylines = polylines, - surfaces = surfaces), + surfaces = surfaces, + is_subclass = TRUE, + attr_names = character(), + flatten_on_exp = character() + ), class = "r2ogs6_gml") } -#'input_add.r2ogs6_gml -#'@description Implementation of generic function input_add for S3 class r2ogs6_gml -#'@param x A r2ogs6_gml class object -#'@param ogs6_obj A OGS6 class object -#'@export -input_add.r2ogs6_gml <- function(x, ogs6_obj) { - ogs6_obj$add_gml(x) -} \ No newline at end of file +#===== Validation utility ===== + + +#'validate_r2ogs6_gml +#'@description Validator for class r2ogs6_gml. Checks if the defined polylines +#' and surfaces reference existing points. +#'@param r2ogs6_gml r2ogs6_gml: +validate_r2ogs6_gml <- function(r2ogs6_gml) { + + maximal_point_id <- length(r2ogs6_gml$points[[1]]) - 1 + + #Check if polylines reference existing points + for(i in seq_len(length(r2ogs6_gml$polylines))){ + for(j in seq_len(length(r2ogs6_gml$polylines[[i]][[2]]))){ + if(r2ogs6_gml$polylines[[i]][[2]][[j]] > maximal_point_id || + r2ogs6_gml$polylines[[i]][[2]][[j]] < 0){ + stop("Polyline references point ID which does not exist", + call. = FALSE) + } + } + } + + #Check if surfaces reference existing points + for(i in seq_len(length(r2ogs6_gml$surfaces))){ + for(j in seq_len(length(r2ogs6_gml$surfaces[[i]][[2]]))){ + if(r2ogs6_gml$surfaces[[i]][[2]][[j]] > maximal_point_id || + r2ogs6_gml$surfaces[[i]][[2]][[j]] < 0 || + r2ogs6_gml$surfaces[[i]][[3]][[j]] > maximal_point_id || + r2ogs6_gml$surfaces[[i]][[3]][[j]] < 0){ + stop("Surface references point ID which does not exist", + call. = FALSE) + } + } + } + + return(invisible(r2ogs6_gml)) +} + + +#'validate_points +#'@description Checks if the input is a tibble, if this tibble has the right +#' number of elements, if those elements are named correctly and if there are +#' any overlapping points or duplicate point names +#'@param points tibble: Must have 3 vectors named 'x', 'y' and 'z', may have +#' optional 'name' vector +validate_points <- function(points) { + + assertthat::assert_that(inherits(points, "tbl_df")) + + names <- names(points) + + if (!((length(points) == 4 && names[[1]] == "x" && names[[2]] == "y" && + names[[3]] == "z" && names[[4]] == "name") || + (length(points) == 3 && names[[1]] == "x" && names[[2]] == "y" && + names[[3]] == "z"))){ + stop(paste(points, " column names do not fit to 'x, y, z, (name)' "), + call. = FALSE) + } + + assertthat::assert_that(is.numeric(points$x)) + assertthat::assert_that(is.numeric(points$y)) + assertthat::assert_that(is.numeric(points$z)) + + has_names <- (length(points) == 4) + + #Find overlapping points and duplicate names + for(i in 1:(length(points[[1]])-1)){ + for(j in (i+1):length(points[[1]])){ + if(points[[1]][[i]] == points[[1]][[j]] && + points[[2]][[i]] == points[[2]][[j]] && + points[[3]][[i]] == points[[3]][[j]]){ + stop("Overlapping .gml points detected", call. = FALSE) + } + + if(has_names){ + if(points[[4]][[i]] == points[[4]][[j]] && + points[[4]][[i]] != ""){ + warning("Duplicate .gml point names detected", + call. = FALSE) + } + } + } + } + + return(invisible(points)) +} + + +#'validate_polylines +#'@description Checks if the input is a list, if this list consists of other +#' lists and if those lists have the correct structure (length of 2, first +#' element is a string named 'name', second element is a numeric vector) +#'@param polylines list(list("foo", c(1, 2))): +validate_polylines <- function(polylines) { + + assertthat::assert_that(is.list(polylines)) + + for(i in seq_len(length(polylines))){ + + assertthat::assert_that(is.list(polylines[[i]])) + assertthat::assert_that(length(polylines[[i]]) == 2) + assertthat::assert_that(assertthat::is.string(polylines[[i]][[1]])) + assertthat::assert_that(is.numeric(polylines[[i]][[2]])) + names(polylines[[i]])[[1]] <- c("name") + names(polylines[[i]])[[2]] <- rep("pnt", + length(names(polylines[[i]])[[2]])) + + #Check for duplicate points / polylines? + } + + names(polylines) <- rep("polyline", length(polylines)) + + return(invisible(polylines)) +} + + +#'validate_surfaces +#'@description Checks if the input is a list, if this list consists of other +#' lists and if those lists have the correct structure (length of 3, first +#' element is a string named 'name', second and third element are numeric +#' vectors) +#'@param surfaces list(list("foo", c(1, 2, 3), c(2, 3, 4))): +validate_surfaces <- function(surfaces) { + + assertthat::assert_that(is.list(surfaces)) + + for(i in 1:length(surfaces)){ + surface <- surfaces[[i]] + + assertthat::assert_that(is.list(surface)) + assertthat::assert_that(length(surface) == 3) + names(surface)[[1]] <- c("name") + + assertthat::assert_that(is.numeric(surface[[2]])) + assertthat::assert_that(length(surface[[2]]) == 3) + names(surface)[[2]] <- c("element") + + assertthat::assert_that(is.numeric(surface[[3]])) + assertthat::assert_that(length(surface[[3]]) == 3) + names(surface)[[3]] <- c("element") + + validate_surface_elements(surface[[2]], surface[[3]]) + + #Check for duplicate points / surfaces? + } + + names(surfaces) <- rep("surface", length(surfaces)) + + return(invisible(surfaces)) +} + + +#'validate_surface_elements +#'@description Helper function, checks if two numerical vectors of length 3 +#' (two surface elements) each consist of 3 different elements and also have +#' exactly 2 matching elements between them which means they describe a valid +#' surface. You can think of the two vectors as two triangles, and the two +#' triangles together form a square which is our surface. +#'@param surface_element_1 numeric, length = 3 +#'@param surface_element_2 numeric, length = 3 +validate_surface_elements = function (surface_element_1, surface_element_2) { + + if(surface_element_1[[1]] == surface_element_1[[2]] || + surface_element_1[[1]] == surface_element_1[[3]] || + surface_element_1[[2]] == surface_element_1[[3]] || + surface_element_2[[1]] == surface_element_2[[2]] || + surface_element_2[[1]] == surface_element_2[[3]] || + surface_element_2[[2]] == surface_element_2[[3]]) { + stop("A surface element must consist of 3 different points", + call. = FALSE) + } + + equal_count <- 0 + + for(i in 1:length(surface_element_1)) { + for(j in 1:length(surface_element_2)) { + if(surface_element_1[[i]] == surface_element_2[[j]]) { + equal_count <- equal_count + 1 + break + } + } + } + + if(equal_count != 2) { + stop("Invalid surface detected", call. = FALSE) + } +}