diff --git a/DESCRIPTION b/DESCRIPTION index 253d664a..f89213a1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -19,7 +19,6 @@ License: MIT + file LICENSE Encoding: UTF-8 LazyData: TRUE Imports: - Rcpp (>= 0.12.2), dplyr, ggforce (>= 0.3.1), grid, @@ -50,7 +49,8 @@ Suggests: covr, sf, sfnetworks -LinkingTo: Rcpp +LinkingTo: + cpp11 RoxygenNote: 7.3.1 Depends: R (>= 2.10), diff --git a/NAMESPACE b/NAMESPACE index e8397916..ca88b6b9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -272,7 +272,6 @@ import(tidygraph) import(vctrs) importFrom(MASS,bandwidth.nrd) importFrom(MASS,kde2d) -importFrom(Rcpp,sourceCpp) importFrom(dplyr,"%>%") importFrom(dplyr,arrange) importFrom(dplyr,do) @@ -420,4 +419,4 @@ importFrom(utils,tail) importFrom(viridis,scale_color_viridis) importFrom(viridis,scale_colour_viridis) importFrom(viridis,scale_fill_viridis) -useDynLib(ggraph) +useDynLib(ggraph, .registration = TRUE) diff --git a/R/RcppExports.R b/R/RcppExports.R deleted file mode 100644 index d1a034ee..00000000 --- a/R/RcppExports.R +++ /dev/null @@ -1,82 +0,0 @@ -# Generated by using Rcpp::compileAttributes() -> do not edit by hand -# Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 - -cactusTree <- function(parent, order, weight, scale, overlap, upright) { - .Call('_ggraph_cactusTree', PACKAGE = 'ggraph', parent, order, weight, scale, overlap, upright) -} - -#' Pack circles together -#' -#' This function is a direct interface to the circle packing algorithm used by -#' \code{\link{layout_tbl_graph_circlepack}}. It takes a vector of sizes and -#' returns the x and y position of each circle as a two-column matrix. -#' -#' @param areas A vector of circle areas -#' -#' @return A matrix with two columns and the same number of rows as the length -#' of the "areas" vector. The matrix has the following attributes added: -#' "enclosing_radius" giving the radius of the smallest enclosing circle, and -#' "front_chain" giving the terminating members of the front chain (see -#' Wang \emph{et al}. 2006). -#' -#' @references -#' Wang, W., Wang, H. H., Dai, G., & Wang, H. (2006). \emph{Visualization of -#' large hierarchical data by circle packing}. Chi, 517-520. -#' -#' @export -#' -#' @examples -#' library(ggforce) -#' sizes <- sample(10, 100, TRUE) -#' -#' position <- pack_circles(sizes) -#' data <- data.frame(x = position[,1], y = position[,2], r = sqrt(sizes/pi)) -#' -#' ggplot() + -#' geom_circle(aes(x0 = x, y0 = y, r = r), data = data, fill = 'steelblue') + -#' geom_circle(aes(x0 = 0, y0 = 0, r = attr(position, 'enclosing_radius'))) + -#' geom_polygon(aes(x = x, y = y), -#' data = data[attr(position, 'front_chain'), ], -#' fill = NA, -#' colour = 'black') -#' -pack_circles <- function(areas) { - .Call('_ggraph_pack', PACKAGE = 'ggraph', areas) -} - -circlePackLayout <- function(parent, weight) { - .Call('_ggraph_circlePackLayout', PACKAGE = 'ggraph', parent, weight) -} - -dendrogram_spread <- function(graph, starts, y, leaf, repel, pad, ratio) { - .Call('_ggraph_dendrogram_spread', PACKAGE = 'ggraph', graph, starts, y, leaf, repel, pad, ratio) -} - -force_bundle_iter <- function(edges_xy, elist, K, C, P, P_rate, S, I, I_rate, compatibility_threshold, eps) { - .Call('_ggraph_force_bundle_iter', PACKAGE = 'ggraph', edges_xy, elist, K, C, P, P_rate, S, I, I_rate, compatibility_threshold, eps) -} - -hTree <- function(parent, order) { - .Call('_ggraph_hTree', PACKAGE = 'ggraph', parent, order) -} - -partitionTree <- function(parent, order, weight, height) { - .Call('_ggraph_partitionTree', PACKAGE = 'ggraph', parent, order, weight, height) -} - -cut_lines <- function(x, y, id, start_width, start_height, end_width, end_height, start_type, end_type) { - .Call('_ggraph_cut_lines', PACKAGE = 'ggraph', x, y, id, start_width, start_height, end_width, end_height, start_type, end_type) -} - -pathAttr <- function(paths, ngroups) { - .Call('_ggraph_pathAttr', PACKAGE = 'ggraph', paths, ngroups) -} - -splitTreemap <- function(parent, order, weight, width, height) { - .Call('_ggraph_splitTreemap', PACKAGE = 'ggraph', parent, order, weight, width, height) -} - -unrooted <- function(parent, order, length, daylight, tol, rotation_mod, maxiter) { - .Call('_ggraph_unrooted', PACKAGE = 'ggraph', parent, order, length, daylight, tol, rotation_mod, maxiter) -} - diff --git a/R/cappedPath.R b/R/cappedPath.R index 50ceb06e..5a494f75 100644 --- a/R/cappedPath.R +++ b/R/cappedPath.R @@ -96,8 +96,15 @@ makeContent.cappedpathgrob <- function(x) { start.cap2 <- convertHeight(x$start.cap2, 'mm', TRUE) end.cap2 <- convertHeight(x$end.cap2, 'mm', TRUE) truncated <- cut_lines( - x_new, y_new, as.integer(x$id), start.cap, start.cap2, - end.cap, end.cap2, x$start.captype, x$end.captype + as.numeric(x_new), + as.numeric(y_new), + as.integer(x$id), + as.numeric(start.cap), + as.numeric(start.cap2), + as.numeric(end.cap), + as.numeric(end.cap2), + as.character(x$start.captype), + as.character(x$end.captype) ) keep <- !is.na(truncated$x) if (!any(keep)) { diff --git a/R/cpp11.R b/R/cpp11.R new file mode 100644 index 00000000..e35713f0 --- /dev/null +++ b/R/cpp11.R @@ -0,0 +1,45 @@ +# Generated by cpp11: do not edit by hand + +cactusTree <- function(parent, order, weight, scale, overlap, upright) { + .Call(`_ggraph_cactusTree`, parent, order, weight, scale, overlap, upright) +} + +pack <- function(areas) { + .Call(`_ggraph_pack`, areas) +} + +circlePackLayout <- function(parent, weight) { + .Call(`_ggraph_circlePackLayout`, parent, weight) +} + +dendrogram_spread <- function(graph, starts, y, leaf, repel, pad, ratio) { + .Call(`_ggraph_dendrogram_spread`, graph, starts, y, leaf, repel, pad, ratio) +} + +force_bundle_iter <- function(edges_xy, K, C, P, P_rate, S, I, I_rate, compatibility_threshold, eps) { + .Call(`_ggraph_force_bundle_iter`, edges_xy, K, C, P, P_rate, S, I, I_rate, compatibility_threshold, eps) +} + +hTree <- function(parent, order) { + .Call(`_ggraph_hTree`, parent, order) +} + +partitionTree <- function(parent, order, weight, height) { + .Call(`_ggraph_partitionTree`, parent, order, weight, height) +} + +cut_lines <- function(x, y, id, start_width, start_height, end_width, end_height, start_type, end_type) { + .Call(`_ggraph_cut_lines`, x, y, id, start_width, start_height, end_width, end_height, start_type, end_type) +} + +pathAttr <- function(group, alpha, width, lty, colour, ngroups) { + .Call(`_ggraph_pathAttr`, group, alpha, width, lty, colour, ngroups) +} + +splitTreemap <- function(parent, order, weight, width, height) { + .Call(`_ggraph_splitTreemap`, parent, order, weight, width, height) +} + +unrooted <- function(parent, order, length, daylight, tol, rotation_mod, maxiter) { + .Call(`_ggraph_unrooted`, parent, order, length, daylight, tol, rotation_mod, maxiter) +} diff --git a/R/geom_edge.R b/R/geom_edge.R index 09837c49..28b14b0e 100644 --- a/R/geom_edge.R +++ b/R/geom_edge.R @@ -30,7 +30,14 @@ GeomEdgePath <- ggproto('GeomEdgePath', GeomPath, if (nrow(data) < 2) { return(zeroGrob()) } - attr <- pathAttr(data, length(unique0(data$group))) + attr <- pathAttr( + as.integer(data$group), + as.numeric(data$edge_alpha), + as.numeric(data$edge_width), + as.character(data$edge_linetype), + as.character(data$edge_colour), + length(unique0(data$group)) + ) if (all(is.na(data$start_cap))) { start_captype <- 'circle' diff --git a/R/geom_edge_bundle_force.R b/R/geom_edge_bundle_force.R index e3b2c427..758b6e56 100644 --- a/R/geom_edge_bundle_force.R +++ b/R/geom_edge_bundle_force.R @@ -280,24 +280,14 @@ force_bundle <- function(data, K, C, P, S, P_rate, I, I_rate, compatibility_thre # initialize matrix with coordinates m <- nrow(data) - elist <- lapply(seq_len(m), function(i) { - matrix(as.vector(data[i, ]), ncol = 2, byrow = TRUE) - }) - # main force bundling routine - elist <- force_bundle_iter( - data, elist, K, C, P, P_rate, - S, I, I_rate, compatibility_threshold, eps - ) + mode(data) <- 'numeric' - # assemble data frame - segments <- nrow(elist[[1]]) - elist <- inject(rbind(!!!elist)) - - data_frame0( - x = elist[, 1], - y = elist[, 2], - group = rep(seq_len(m), each = segments) + # main force bundling routine + force_bundle_iter( + data, as.numeric(K), as.integer(C), as.integer(P), as.integer(P_rate), + as.numeric(S), as.integer(I), as.numeric(I_rate), + as.numeric(compatibility_threshold), as.numeric(eps) ) } diff --git a/R/ggraph-package.R b/R/ggraph-package.R index cfb6c680..7fe9d767 100644 --- a/R/ggraph-package.R +++ b/R/ggraph-package.R @@ -7,7 +7,6 @@ #' @import ggplot2 tidygraph rlang vctrs #' @importFrom memoise memoise #' @importFrom lifecycle deprecated -#' @importFrom Rcpp sourceCpp -#' @useDynLib ggraph +#' @useDynLib ggraph, .registration = TRUE ## usethis namespace: end NULL diff --git a/R/layout_cactustree.R b/R/layout_cactustree.R index 5eeb18c5..b6886250 100644 --- a/R/layout_cactustree.R +++ b/R/layout_cactustree.R @@ -50,7 +50,14 @@ layout_tbl_graph_cactustree <- function(graph, direction = "out", weight = NULL, weight <- as.numeric(degree(graph, mode = direction) == 0) } hierarchy <- tree_to_hierarchy(graph, direction, NULL, weight, NULL) - layout <- cactusTree(hierarchy$parent, hierarchy$order, hierarchy$weight, scale_factor, overlap, upright)[-1, ] + layout <- cactusTree( + as.integer(hierarchy$parent), + as.integer(hierarchy$order), + as.numeric(hierarchy$weight), + as.numeric(scale_factor), + as.numeric(overlap), + as.logical(upright) + )[-1, ] nodes <- data_frame0( x = layout[, 1], y = layout[, 2], diff --git a/R/layout_circlepack.R b/R/layout_circlepack.R index 6772c49c..bcded3be 100644 --- a/R/layout_circlepack.R +++ b/R/layout_circlepack.R @@ -56,7 +56,10 @@ layout_tbl_graph_circlepack <- function(graph, weight = NULL, circular = FALSE, sort.by <- enquo(sort.by) sort.by <- eval_tidy(sort.by, .N()) hierarchy <- tree_to_hierarchy(graph, direction, sort.by, weight) - nodes <- circlePackLayout(hierarchy$parent, hierarchy$weight)[-1, ] + nodes <- circlePackLayout( + as.integer(hierarchy$parent), + as.numeric(hierarchy$weight) + )[-1, ] nodes <- data_frame0( x = nodes[, 1], y = nodes[, 2], diff --git a/R/layout_dendrogram.R b/R/layout_dendrogram.R index 885abeb0..748263c2 100644 --- a/R/layout_dendrogram.R +++ b/R/layout_dendrogram.R @@ -78,7 +78,15 @@ layout_tbl_graph_dendrogram <- function(graph, circular = FALSE, offset = pi / 2 startnode <- which(degree(graph, mode = reverse_dir) == 0) if (length(startnode) < 1) cli::cli_abort('The graph doesn\'t contain a root node') neighbors <- lapply(adjacent_vertices(graph, seq_len(gorder(graph)), direction), as.integer) - nodes$x <- dendrogram_spread(neighbors, startnode, nodes$y, nodes$leaf, repel, pad, ratio) + nodes$x <- dendrogram_spread( + neighbors, + as.integer(startnode), + as.numeric(nodes$y), + as.logical(nodes$leaf), + as.logical(repel), + as.numeric(pad), + as.numeric(ratio) + ) graph <- add_direction(graph, nodes) if (circular) { radial <- radial_trans( diff --git a/R/layout_htree.R b/R/layout_htree.R index e33b4186..dc45bfab 100644 --- a/R/layout_htree.R +++ b/R/layout_htree.R @@ -38,7 +38,7 @@ layout_tbl_graph_htree <- function(graph, sort.by = NULL, direction = 'out', cir sort.by <- enquo(sort.by) sort.by <- eval_tidy(sort.by, .N()) hierarchy <- tree_to_hierarchy(graph, direction, sort.by, NULL) - layout <- hTree(hierarchy$parent, hierarchy$order)[-1, ] + layout <- hTree(as.integer(hierarchy$parent), as.integer(hierarchy$order))[-1, ] nodes <- data_frame0( x = layout[, 1], y = layout[, 2], diff --git a/R/layout_partition.R b/R/layout_partition.R index 57888ba5..11a02766 100644 --- a/R/layout_partition.R +++ b/R/layout_partition.R @@ -65,7 +65,12 @@ layout_tbl_graph_partition <- function(graph, weight = NULL, circular = FALSE, h sort.by <- enquo(sort.by) sort.by <- eval_tidy(sort.by, .N()) hierarchy <- tree_to_hierarchy(graph, direction, sort.by, weight, height) - layout <- partitionTree(hierarchy$parent, hierarchy$order, hierarchy$weight, hierarchy$height)[-1, ] + layout <- partitionTree( + as.integer(hierarchy$parent), + as.integer(hierarchy$order), + as.numeric(hierarchy$weight), + as.numeric(hierarchy$height) + )[-1, ] if (circular) { if (const.area) { y0 <- sqrt(layout[, 2]) diff --git a/R/layout_treemap.R b/R/layout_treemap.R index f2bbc3f0..2899a372 100644 --- a/R/layout_treemap.R +++ b/R/layout_treemap.R @@ -77,7 +77,13 @@ layout_tbl_graph_treemap <- function(graph, algorithm = 'split', weight = NULL, hierarchy <- tree_to_hierarchy(graph, direction, sort.by, weight) layout <- switch( algorithm, - split = splitTreemap(hierarchy$parent, hierarchy$order, hierarchy$weight, width, height), + split = splitTreemap( + as.integer(hierarchy$parent), + as.integer(hierarchy$order), + as.numeric(hierarchy$weight), + as.numeric(width), + as.numeric(height) + ), cli::cli_abort('Unknown treemap algorithm') )[-1, ] nodes <- data_frame0( diff --git a/R/layout_unrooted.R b/R/layout_unrooted.R index 427f8464..db808825 100644 --- a/R/layout_unrooted.R +++ b/R/layout_unrooted.R @@ -43,7 +43,15 @@ layout_tbl_graph_unrooted <- function(graph, daylight = TRUE, length = NULL, tol length <- enquo(length) length <- eval_tidy(length, .E()) hierarchy <- tree_to_hierarchy(graph, 'out', seq_len(gorder(graph)), weight = NULL, length) - layout <- unrooted(hierarchy$parent, hierarchy$order, hierarchy$height, daylight, tolerance, rotation_mod, maxiter)[-1, ] + layout <- unrooted( + as.integer(hierarchy$parent), + as.integer(hierarchy$order), + as.numeric(hierarchy$height), + as.logical(daylight), + as.numeric(tolerance), + as.numeric(rotation_mod), + as.integer(maxiter) + )[-1, ] nodes <- data_frame0( x = layout[, 1], y = layout[, 2], diff --git a/R/pack.R b/R/pack.R new file mode 100644 index 00000000..c9f0996a --- /dev/null +++ b/R/pack.R @@ -0,0 +1,38 @@ +#' Pack circles together +#' +#' This function is a direct interface to the circle packing algorithm used by +#' \code{\link{layout_tbl_graph_circlepack}}. It takes a vector of sizes and +#' returns the x and y position of each circle as a two-column matrix. +#' +#' @param areas A vector of circle areas +#' +#' @return A matrix with two columns and the same number of rows as the length +#' of the "areas" vector. The matrix has the following attributes added: +#' "enclosing_radius" giving the radius of the smallest enclosing circle, and +#' "front_chain" giving the terminating members of the front chain (see +#' Wang \emph{et al}. 2006). +#' +#' @references +#' Wang, W., Wang, H. H., Dai, G., & Wang, H. (2006). \emph{Visualization of +#' large hierarchical data by circle packing}. Chi, 517-520. +#' +#' @export +#' +#' @examples +#' library(ggforce) +#' sizes <- sample(10, 100, TRUE) +#' +#' position <- pack_circles(sizes) +#' data <- data.frame(x = position[,1], y = position[,2], r = sqrt(sizes/pi)) +#' +#' ggplot() + +#' geom_circle(aes(x0 = x, y0 = y, r = r), data = data, fill = 'steelblue') + +#' geom_circle(aes(x0 = 0, y0 = 0, r = attr(position, 'enclosing_radius'))) + +#' geom_polygon(aes(x = x, y = y), +#' data = data[attr(position, 'front_chain'), ], +#' fill = NA, +#' colour = 'black') +#' +pack_circles <- function(areas) { + pack(as.numeric(areas)) +} diff --git a/man/pack_circles.Rd b/man/pack_circles.Rd index a3ee6e8a..cdd08415 100644 --- a/man/pack_circles.Rd +++ b/man/pack_circles.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/RcppExports.R +% Please edit documentation in R/pack.R \name{pack_circles} \alias{pack_circles} \title{Pack circles together} diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 00000000..22034c46 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,3 @@ +*.o +*.so +*.dll diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp deleted file mode 100644 index bc730157..00000000 --- a/src/RcppExports.cpp +++ /dev/null @@ -1,198 +0,0 @@ -// Generated by using Rcpp::compileAttributes() -> do not edit by hand -// Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393 - -#include - -using namespace Rcpp; - -#ifdef RCPP_USE_GLOBAL_ROSTREAM -Rcpp::Rostream& Rcpp::Rcout = Rcpp::Rcpp_cout_get(); -Rcpp::Rostream& Rcpp::Rcerr = Rcpp::Rcpp_cerr_get(); -#endif - -// cactusTree -NumericMatrix cactusTree(IntegerVector parent, IntegerVector order, NumericVector weight, double scale, double overlap, bool upright); -RcppExport SEXP _ggraph_cactusTree(SEXP parentSEXP, SEXP orderSEXP, SEXP weightSEXP, SEXP scaleSEXP, SEXP overlapSEXP, SEXP uprightSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerVector >::type parent(parentSEXP); - Rcpp::traits::input_parameter< IntegerVector >::type order(orderSEXP); - Rcpp::traits::input_parameter< NumericVector >::type weight(weightSEXP); - Rcpp::traits::input_parameter< double >::type scale(scaleSEXP); - Rcpp::traits::input_parameter< double >::type overlap(overlapSEXP); - Rcpp::traits::input_parameter< bool >::type upright(uprightSEXP); - rcpp_result_gen = Rcpp::wrap(cactusTree(parent, order, weight, scale, overlap, upright)); - return rcpp_result_gen; -END_RCPP -} -// pack -NumericMatrix pack(NumericVector areas); -RcppExport SEXP _ggraph_pack(SEXP areasSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< NumericVector >::type areas(areasSEXP); - rcpp_result_gen = Rcpp::wrap(pack(areas)); - return rcpp_result_gen; -END_RCPP -} -// circlePackLayout -NumericMatrix circlePackLayout(IntegerVector parent, NumericVector weight); -RcppExport SEXP _ggraph_circlePackLayout(SEXP parentSEXP, SEXP weightSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerVector >::type parent(parentSEXP); - Rcpp::traits::input_parameter< NumericVector >::type weight(weightSEXP); - rcpp_result_gen = Rcpp::wrap(circlePackLayout(parent, weight)); - return rcpp_result_gen; -END_RCPP -} -// dendrogram_spread -NumericVector dendrogram_spread(ListOf graph, IntegerVector starts, NumericVector y, LogicalVector leaf, bool repel, double pad, double ratio); -RcppExport SEXP _ggraph_dendrogram_spread(SEXP graphSEXP, SEXP startsSEXP, SEXP ySEXP, SEXP leafSEXP, SEXP repelSEXP, SEXP padSEXP, SEXP ratioSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< ListOf >::type graph(graphSEXP); - Rcpp::traits::input_parameter< IntegerVector >::type starts(startsSEXP); - Rcpp::traits::input_parameter< NumericVector >::type y(ySEXP); - Rcpp::traits::input_parameter< LogicalVector >::type leaf(leafSEXP); - Rcpp::traits::input_parameter< bool >::type repel(repelSEXP); - Rcpp::traits::input_parameter< double >::type pad(padSEXP); - Rcpp::traits::input_parameter< double >::type ratio(ratioSEXP); - rcpp_result_gen = Rcpp::wrap(dendrogram_spread(graph, starts, y, leaf, repel, pad, ratio)); - return rcpp_result_gen; -END_RCPP -} -// force_bundle_iter -List force_bundle_iter(NumericMatrix edges_xy, List elist, double K, int C, int P, int P_rate, double S, int I, double I_rate, double compatibility_threshold, double eps); -RcppExport SEXP _ggraph_force_bundle_iter(SEXP edges_xySEXP, SEXP elistSEXP, SEXP KSEXP, SEXP CSEXP, SEXP PSEXP, SEXP P_rateSEXP, SEXP SSEXP, SEXP ISEXP, SEXP I_rateSEXP, SEXP compatibility_thresholdSEXP, SEXP epsSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< NumericMatrix >::type edges_xy(edges_xySEXP); - Rcpp::traits::input_parameter< List >::type elist(elistSEXP); - Rcpp::traits::input_parameter< double >::type K(KSEXP); - Rcpp::traits::input_parameter< int >::type C(CSEXP); - Rcpp::traits::input_parameter< int >::type P(PSEXP); - Rcpp::traits::input_parameter< int >::type P_rate(P_rateSEXP); - Rcpp::traits::input_parameter< double >::type S(SSEXP); - Rcpp::traits::input_parameter< int >::type I(ISEXP); - Rcpp::traits::input_parameter< double >::type I_rate(I_rateSEXP); - Rcpp::traits::input_parameter< double >::type compatibility_threshold(compatibility_thresholdSEXP); - Rcpp::traits::input_parameter< double >::type eps(epsSEXP); - rcpp_result_gen = Rcpp::wrap(force_bundle_iter(edges_xy, elist, K, C, P, P_rate, S, I, I_rate, compatibility_threshold, eps)); - return rcpp_result_gen; -END_RCPP -} -// hTree -NumericMatrix hTree(IntegerVector parent, IntegerVector order); -RcppExport SEXP _ggraph_hTree(SEXP parentSEXP, SEXP orderSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerVector >::type parent(parentSEXP); - Rcpp::traits::input_parameter< IntegerVector >::type order(orderSEXP); - rcpp_result_gen = Rcpp::wrap(hTree(parent, order)); - return rcpp_result_gen; -END_RCPP -} -// partitionTree -NumericMatrix partitionTree(IntegerVector parent, IntegerVector order, NumericVector weight, NumericVector height); -RcppExport SEXP _ggraph_partitionTree(SEXP parentSEXP, SEXP orderSEXP, SEXP weightSEXP, SEXP heightSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerVector >::type parent(parentSEXP); - Rcpp::traits::input_parameter< IntegerVector >::type order(orderSEXP); - Rcpp::traits::input_parameter< NumericVector >::type weight(weightSEXP); - Rcpp::traits::input_parameter< NumericVector >::type height(heightSEXP); - rcpp_result_gen = Rcpp::wrap(partitionTree(parent, order, weight, height)); - return rcpp_result_gen; -END_RCPP -} -// cut_lines -List cut_lines(NumericVector x, NumericVector y, IntegerVector id, NumericVector start_width, NumericVector start_height, NumericVector end_width, NumericVector end_height, CharacterVector start_type, CharacterVector end_type); -RcppExport SEXP _ggraph_cut_lines(SEXP xSEXP, SEXP ySEXP, SEXP idSEXP, SEXP start_widthSEXP, SEXP start_heightSEXP, SEXP end_widthSEXP, SEXP end_heightSEXP, SEXP start_typeSEXP, SEXP end_typeSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< NumericVector >::type x(xSEXP); - Rcpp::traits::input_parameter< NumericVector >::type y(ySEXP); - Rcpp::traits::input_parameter< IntegerVector >::type id(idSEXP); - Rcpp::traits::input_parameter< NumericVector >::type start_width(start_widthSEXP); - Rcpp::traits::input_parameter< NumericVector >::type start_height(start_heightSEXP); - Rcpp::traits::input_parameter< NumericVector >::type end_width(end_widthSEXP); - Rcpp::traits::input_parameter< NumericVector >::type end_height(end_heightSEXP); - Rcpp::traits::input_parameter< CharacterVector >::type start_type(start_typeSEXP); - Rcpp::traits::input_parameter< CharacterVector >::type end_type(end_typeSEXP); - rcpp_result_gen = Rcpp::wrap(cut_lines(x, y, id, start_width, start_height, end_width, end_height, start_type, end_type)); - return rcpp_result_gen; -END_RCPP -} -// pathAttr -DataFrame pathAttr(DataFrame paths, int ngroups); -RcppExport SEXP _ggraph_pathAttr(SEXP pathsSEXP, SEXP ngroupsSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< DataFrame >::type paths(pathsSEXP); - Rcpp::traits::input_parameter< int >::type ngroups(ngroupsSEXP); - rcpp_result_gen = Rcpp::wrap(pathAttr(paths, ngroups)); - return rcpp_result_gen; -END_RCPP -} -// splitTreemap -NumericMatrix splitTreemap(IntegerVector parent, IntegerVector order, NumericVector weight, double width, double height); -RcppExport SEXP _ggraph_splitTreemap(SEXP parentSEXP, SEXP orderSEXP, SEXP weightSEXP, SEXP widthSEXP, SEXP heightSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerVector >::type parent(parentSEXP); - Rcpp::traits::input_parameter< IntegerVector >::type order(orderSEXP); - Rcpp::traits::input_parameter< NumericVector >::type weight(weightSEXP); - Rcpp::traits::input_parameter< double >::type width(widthSEXP); - Rcpp::traits::input_parameter< double >::type height(heightSEXP); - rcpp_result_gen = Rcpp::wrap(splitTreemap(parent, order, weight, width, height)); - return rcpp_result_gen; -END_RCPP -} -// unrooted -NumericMatrix unrooted(IntegerVector parent, IntegerVector order, NumericVector length, bool daylight, double tol, double rotation_mod, int maxiter); -RcppExport SEXP _ggraph_unrooted(SEXP parentSEXP, SEXP orderSEXP, SEXP lengthSEXP, SEXP daylightSEXP, SEXP tolSEXP, SEXP rotation_modSEXP, SEXP maxiterSEXP) { -BEGIN_RCPP - Rcpp::RObject rcpp_result_gen; - Rcpp::RNGScope rcpp_rngScope_gen; - Rcpp::traits::input_parameter< IntegerVector >::type parent(parentSEXP); - Rcpp::traits::input_parameter< IntegerVector >::type order(orderSEXP); - Rcpp::traits::input_parameter< NumericVector >::type length(lengthSEXP); - Rcpp::traits::input_parameter< bool >::type daylight(daylightSEXP); - Rcpp::traits::input_parameter< double >::type tol(tolSEXP); - Rcpp::traits::input_parameter< double >::type rotation_mod(rotation_modSEXP); - Rcpp::traits::input_parameter< int >::type maxiter(maxiterSEXP); - rcpp_result_gen = Rcpp::wrap(unrooted(parent, order, length, daylight, tol, rotation_mod, maxiter)); - return rcpp_result_gen; -END_RCPP -} - -static const R_CallMethodDef CallEntries[] = { - {"_ggraph_cactusTree", (DL_FUNC) &_ggraph_cactusTree, 6}, - {"_ggraph_pack", (DL_FUNC) &_ggraph_pack, 1}, - {"_ggraph_circlePackLayout", (DL_FUNC) &_ggraph_circlePackLayout, 2}, - {"_ggraph_dendrogram_spread", (DL_FUNC) &_ggraph_dendrogram_spread, 7}, - {"_ggraph_force_bundle_iter", (DL_FUNC) &_ggraph_force_bundle_iter, 11}, - {"_ggraph_hTree", (DL_FUNC) &_ggraph_hTree, 2}, - {"_ggraph_partitionTree", (DL_FUNC) &_ggraph_partitionTree, 4}, - {"_ggraph_cut_lines", (DL_FUNC) &_ggraph_cut_lines, 9}, - {"_ggraph_pathAttr", (DL_FUNC) &_ggraph_pathAttr, 2}, - {"_ggraph_splitTreemap", (DL_FUNC) &_ggraph_splitTreemap, 5}, - {"_ggraph_unrooted", (DL_FUNC) &_ggraph_unrooted, 7}, - {NULL, NULL, 0} -}; - -RcppExport void R_init_ggraph(DllInfo *dll) { - R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); - R_useDynamicSymbols(dll, FALSE); -} diff --git a/src/cactusTree.cpp b/src/cactusTree.cpp index c5a24f8e..eeafdfcd 100644 --- a/src/cactusTree.cpp +++ b/src/cactusTree.cpp @@ -1,6 +1,10 @@ -#include #include "nodes.h" -using namespace Rcpp; + +#include +#include +#include + +#include void cactusTreeCircle(Node* node, double x, double y, double scale, double alpha, double span, double overlap) { Rectangle r = {x, y, std::pow(node->weight(), scale), 0.0}; @@ -17,15 +21,10 @@ void cactusTreeCircle(Node* node, double x, double y, double scale, double alpha total_angle += std::pow(children[i]->weight(), scale * (children.size() < 5 ? 2 : 0.75)); ordered_children.insert(ordered_children.begin() + int(ordered_children.size() / 2), children[i]); } - //std::reverse(ordered_children.begin(), ordered_children.end()); - //for (unsigned int i = 1; i < children.size(); i+=2) { - // ordered_children.push_back(children[i]); - //} - alpha -= span / 2; + alpha -= span / 2; for (unsigned int i = 0; i < ordered_children.size(); i++) { - //Rprintf("%f ", ordered_children[i]->weight()); double local_span = 0.5 * span * std::pow(ordered_children[i]->weight(), scale * (children.size() < 5 ? 2 : 0.75)) / total_angle; alpha += local_span; double child_r = std::pow(ordered_children[i]->weight(), scale); @@ -35,15 +34,14 @@ void cactusTreeCircle(Node* node, double x, double y, double scale, double alpha cactusTreeCircle(ordered_children[i], x2, y2, scale, alpha, 3.926991, overlap); alpha += local_span; } - //Rprintf("\n"); } -//[[Rcpp::export]] -NumericMatrix cactusTree(IntegerVector parent, IntegerVector order, NumericVector weight, double scale, double overlap, bool upright) { - NumericMatrix circ(parent.size(), 3); +[[cpp11::register]] +cpp11::writable::doubles_matrix<> cactusTree(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, double scale, double overlap, bool upright) { + cpp11::writable::doubles_matrix<> circ(parent.size(), 3); unsigned int i; - std::vector nodes = createHierarchy(as< std::vector >(parent), as< std::vector >(order), as< std::vector >(weight)); + std::vector nodes = createHierarchy(parent, order, weight); Node* startNode = nodes[0]->getRoot(); startNode->tallyWeights(); diff --git a/src/circlePack.cpp b/src/circlePack.cpp index e4202e3c..1032741e 100644 --- a/src/circlePack.cpp +++ b/src/circlePack.cpp @@ -1,7 +1,13 @@ -#include #include -using namespace Rcpp; +#include +#include +#include +#include +#include + +#include +#include struct randWrapper { using result_type = unsigned int; @@ -99,7 +105,7 @@ class FrontChain { Circle enclose1(Circle* c1) { Circle enc = {c1->x, c1->y, c1->r}; if (enc.r > 1e10 || enc.r < 0) { - stop("enc1 error"); + cpp11::stop("enc1 error"); } return enc; }; @@ -114,7 +120,7 @@ class FrontChain { (l + c1->r + c2->r) / 2 }; if (enc.r > 1e10 || enc.r < 0) { - stop("enc2 error"); + cpp11::stop("enc2 error"); } return enc; }; @@ -143,7 +149,7 @@ class FrontChain { r }; if (enc.r > 1e10 || enc.r < 0) { - stop("enc3 error"); + cpp11::stop("enc3 error"); } return enc; }; @@ -179,7 +185,7 @@ class FrontChain { c1->x = 0; c1->y = 0; double d12 = c1->r + c2->r; - double angle2 = (2 * M_PI) * R::runif(0, 1); + double angle2 = (2 * M_PI) * unif_rand(); c2->x = std::cos(float(angle2)) * d12; c2->y = std::sin(float(angle2)) * d12; @@ -200,7 +206,7 @@ class FrontChain { c1->x = 0; c1->y = 0; double d12 = c1->r + c2->r; - double angle2 = (2 * M_PI) * R::runif(0, 1); + double angle2 = (2 * M_PI) * unif_rand(); c2->x = std::cos(float(angle2)) * d12; c2->y = std::sin(float(angle2)) * d12; @@ -313,7 +319,7 @@ class FrontChain { FrontChain pack_circles(std::deque &circles) { if (circles.size() == 0) { - stop("Cannot pack an empty set of circles"); + cpp11::stop("Cannot pack an empty set of circles"); } std::deque::iterator itc; @@ -403,14 +409,13 @@ class NodePack { } } }; -std::vector createHierarchy(std::vector parent, std::vector weight) { +std::vector createHierarchy(cpp11::integers &parent, cpp11::doubles &weight) { std::vector nodes; - unsigned int i; - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { NodePack* node = new NodePack(i + 1, weight[i]); nodes.push_back(node); } - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { if (parent[i] >= 0) { nodes[parent[i]]->addNode(nodes[i]); } @@ -427,58 +432,23 @@ int findTopNode(std::vector& nodes) { } } if (!found) { - stop("No top node. Is this a tree structure?"); + cpp11::stop("No top node. Is this a tree structure?"); } return (int) i; } -//' Pack circles together -//' -//' This function is a direct interface to the circle packing algorithm used by -//' \code{\link{layout_tbl_graph_circlepack}}. It takes a vector of sizes and -//' returns the x and y position of each circle as a two-column matrix. -//' -//' @param areas A vector of circle areas -//' -//' @return A matrix with two columns and the same number of rows as the length -//' of the "areas" vector. The matrix has the following attributes added: -//' "enclosing_radius" giving the radius of the smallest enclosing circle, and -//' "front_chain" giving the terminating members of the front chain (see -//' Wang \emph{et al}. 2006). -//' -//' @references -//' Wang, W., Wang, H. H., Dai, G., & Wang, H. (2006). \emph{Visualization of -//' large hierarchical data by circle packing}. Chi, 517-520. -//' -//' @export -//' -//' @examples -//' library(ggforce) -//' sizes <- sample(10, 100, TRUE) -//' -//' position <- pack_circles(sizes) -//' data <- data.frame(x = position[,1], y = position[,2], r = sqrt(sizes/pi)) -//' -//' ggplot() + -//' geom_circle(aes(x0 = x, y0 = y, r = r), data = data, fill = 'steelblue') + -//' geom_circle(aes(x0 = 0, y0 = 0, r = attr(position, 'enclosing_radius'))) + -//' geom_polygon(aes(x = x, y = y), -//' data = data[attr(position, 'front_chain'), ], -//' fill = NA, -//' colour = 'black') -//' -//[[Rcpp::export(name = "pack_circles")]] -NumericMatrix pack(NumericVector areas) { + +[[cpp11::register]] +cpp11::writable::doubles_matrix<> pack(cpp11::doubles areas) { GetRNGstate(); - NumericVector::iterator itr; std::deque circles; - NumericMatrix res(areas.size(), 2); - for (itr = areas.begin(); itr != areas.end(); itr++) { - Circle c = {0, 0, std::sqrt(float(*itr / M_PI)), static_cast(circles.size()) + 1}; + cpp11::writable::doubles_matrix<> res(areas.size(), 2); + for (R_xlen_t i = 0; i < areas.size(); ++i) { + Circle c = {0, 0, std::sqrt(areas[i] / M_PI), static_cast(circles.size()) + 1}; circles.push_back(c); } if (circles.size() == 0) { res.attr("enclosing_radius") = 0; - res.attr("front_chain") = IntegerVector(0); + res.attr("front_chain") = cpp11::writable::integers(); } else { FrontChain fc = pack_circles(circles); @@ -487,19 +457,20 @@ NumericMatrix pack(NumericVector areas) { res(i, 1) = circles[i].y; } - res.attr("enclosing_radius") = fc.enclose_radius(); - res.attr("front_chain") = wrap(fc.chain_ind()); + res.attr("enclosing_radius") = Rf_ScalarReal(fc.enclose_radius()); + auto chain_ind = fc.chain_ind(); + res.attr("front_chain") = cpp11::writable::integers(chain_ind.begin(), chain_ind.end()); } PutRNGstate(); return res; } -//[[Rcpp::export]] -NumericMatrix circlePackLayout(IntegerVector parent, NumericVector weight) { +[[cpp11::register]] +cpp11::writable::doubles_matrix<> circlePackLayout(cpp11::integers parent, cpp11::doubles weight) { GetRNGstate(); - NumericMatrix res(parent.size(), 3); + cpp11::writable::doubles_matrix<> res(parent.size(), 3); unsigned int i; - std::vector nodes = createHierarchy(as< std::vector >(parent), as< std::vector >(weight)); + std::vector nodes = createHierarchy(parent, weight); int startNode = findTopNode(nodes); diff --git a/src/cpp11.cpp b/src/cpp11.cpp new file mode 100644 index 00000000..859ffaf3 --- /dev/null +++ b/src/cpp11.cpp @@ -0,0 +1,107 @@ +// Generated by cpp11: do not edit by hand +// clang-format off + + +#include "cpp11/declarations.hpp" +#include + +// cactusTree.cpp +cpp11::writable::doubles_matrix<> cactusTree(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, double scale, double overlap, bool upright); +extern "C" SEXP _ggraph_cactusTree(SEXP parent, SEXP order, SEXP weight, SEXP scale, SEXP overlap, SEXP upright) { + BEGIN_CPP11 + return cpp11::as_sexp(cactusTree(cpp11::as_cpp>(parent), cpp11::as_cpp>(order), cpp11::as_cpp>(weight), cpp11::as_cpp>(scale), cpp11::as_cpp>(overlap), cpp11::as_cpp>(upright))); + END_CPP11 +} +// circlePack.cpp +cpp11::writable::doubles_matrix<> pack(cpp11::doubles areas); +extern "C" SEXP _ggraph_pack(SEXP areas) { + BEGIN_CPP11 + return cpp11::as_sexp(pack(cpp11::as_cpp>(areas))); + END_CPP11 +} +// circlePack.cpp +cpp11::writable::doubles_matrix<> circlePackLayout(cpp11::integers parent, cpp11::doubles weight); +extern "C" SEXP _ggraph_circlePackLayout(SEXP parent, SEXP weight) { + BEGIN_CPP11 + return cpp11::as_sexp(circlePackLayout(cpp11::as_cpp>(parent), cpp11::as_cpp>(weight))); + END_CPP11 +} +// dendrogram.cpp +cpp11::writable::doubles dendrogram_spread(cpp11::list_of graph, cpp11::integers starts, cpp11::doubles y, cpp11::logicals leaf, bool repel, double pad, double ratio); +extern "C" SEXP _ggraph_dendrogram_spread(SEXP graph, SEXP starts, SEXP y, SEXP leaf, SEXP repel, SEXP pad, SEXP ratio) { + BEGIN_CPP11 + return cpp11::as_sexp(dendrogram_spread(cpp11::as_cpp>>(graph), cpp11::as_cpp>(starts), cpp11::as_cpp>(y), cpp11::as_cpp>(leaf), cpp11::as_cpp>(repel), cpp11::as_cpp>(pad), cpp11::as_cpp>(ratio))); + END_CPP11 +} +// forceBundle.cpp +cpp11::writable::data_frame force_bundle_iter(cpp11::doubles_matrix<> edges_xy, double K, int C, int P, int P_rate, double S, int I, double I_rate, double compatibility_threshold, double eps); +extern "C" SEXP _ggraph_force_bundle_iter(SEXP edges_xy, SEXP K, SEXP C, SEXP P, SEXP P_rate, SEXP S, SEXP I, SEXP I_rate, SEXP compatibility_threshold, SEXP eps) { + BEGIN_CPP11 + return cpp11::as_sexp(force_bundle_iter(cpp11::as_cpp>>(edges_xy), cpp11::as_cpp>(K), cpp11::as_cpp>(C), cpp11::as_cpp>(P), cpp11::as_cpp>(P_rate), cpp11::as_cpp>(S), cpp11::as_cpp>(I), cpp11::as_cpp>(I_rate), cpp11::as_cpp>(compatibility_threshold), cpp11::as_cpp>(eps))); + END_CPP11 +} +// hTree.cpp +cpp11::writable::doubles_matrix<> hTree(cpp11::integers parent, cpp11::integers order); +extern "C" SEXP _ggraph_hTree(SEXP parent, SEXP order) { + BEGIN_CPP11 + return cpp11::as_sexp(hTree(cpp11::as_cpp>(parent), cpp11::as_cpp>(order))); + END_CPP11 +} +// iciclePlot.cpp +cpp11::writable::doubles_matrix<> partitionTree(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, cpp11::doubles height); +extern "C" SEXP _ggraph_partitionTree(SEXP parent, SEXP order, SEXP weight, SEXP height) { + BEGIN_CPP11 + return cpp11::as_sexp(partitionTree(cpp11::as_cpp>(parent), cpp11::as_cpp>(order), cpp11::as_cpp>(weight), cpp11::as_cpp>(height))); + END_CPP11 +} +// lineCutter.cpp +cpp11::writable::data_frame cut_lines(cpp11::doubles x, cpp11::doubles y, cpp11::integers id, cpp11::doubles start_width, cpp11::doubles start_height, cpp11::doubles end_width, cpp11::doubles end_height, cpp11::strings start_type, cpp11::strings end_type); +extern "C" SEXP _ggraph_cut_lines(SEXP x, SEXP y, SEXP id, SEXP start_width, SEXP start_height, SEXP end_width, SEXP end_height, SEXP start_type, SEXP end_type) { + BEGIN_CPP11 + return cpp11::as_sexp(cut_lines(cpp11::as_cpp>(x), cpp11::as_cpp>(y), cpp11::as_cpp>(id), cpp11::as_cpp>(start_width), cpp11::as_cpp>(start_height), cpp11::as_cpp>(end_width), cpp11::as_cpp>(end_height), cpp11::as_cpp>(start_type), cpp11::as_cpp>(end_type))); + END_CPP11 +} +// pathAttr.cpp +cpp11::writable::data_frame pathAttr(cpp11::integers group, cpp11::doubles alpha, cpp11::doubles width, cpp11::strings lty, cpp11::strings colour, int ngroups); +extern "C" SEXP _ggraph_pathAttr(SEXP group, SEXP alpha, SEXP width, SEXP lty, SEXP colour, SEXP ngroups) { + BEGIN_CPP11 + return cpp11::as_sexp(pathAttr(cpp11::as_cpp>(group), cpp11::as_cpp>(alpha), cpp11::as_cpp>(width), cpp11::as_cpp>(lty), cpp11::as_cpp>(colour), cpp11::as_cpp>(ngroups))); + END_CPP11 +} +// treemap.cpp +cpp11::writable::doubles_matrix<> splitTreemap(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, double width, double height); +extern "C" SEXP _ggraph_splitTreemap(SEXP parent, SEXP order, SEXP weight, SEXP width, SEXP height) { + BEGIN_CPP11 + return cpp11::as_sexp(splitTreemap(cpp11::as_cpp>(parent), cpp11::as_cpp>(order), cpp11::as_cpp>(weight), cpp11::as_cpp>(width), cpp11::as_cpp>(height))); + END_CPP11 +} +// unrooted.cpp +cpp11::writable::doubles_matrix<> unrooted(cpp11::integers parent, cpp11::integers order, cpp11::doubles length, bool daylight, double tol, double rotation_mod, int maxiter); +extern "C" SEXP _ggraph_unrooted(SEXP parent, SEXP order, SEXP length, SEXP daylight, SEXP tol, SEXP rotation_mod, SEXP maxiter) { + BEGIN_CPP11 + return cpp11::as_sexp(unrooted(cpp11::as_cpp>(parent), cpp11::as_cpp>(order), cpp11::as_cpp>(length), cpp11::as_cpp>(daylight), cpp11::as_cpp>(tol), cpp11::as_cpp>(rotation_mod), cpp11::as_cpp>(maxiter))); + END_CPP11 +} + +extern "C" { +static const R_CallMethodDef CallEntries[] = { + {"_ggraph_cactusTree", (DL_FUNC) &_ggraph_cactusTree, 6}, + {"_ggraph_circlePackLayout", (DL_FUNC) &_ggraph_circlePackLayout, 2}, + {"_ggraph_cut_lines", (DL_FUNC) &_ggraph_cut_lines, 9}, + {"_ggraph_dendrogram_spread", (DL_FUNC) &_ggraph_dendrogram_spread, 7}, + {"_ggraph_force_bundle_iter", (DL_FUNC) &_ggraph_force_bundle_iter, 10}, + {"_ggraph_hTree", (DL_FUNC) &_ggraph_hTree, 2}, + {"_ggraph_pack", (DL_FUNC) &_ggraph_pack, 1}, + {"_ggraph_partitionTree", (DL_FUNC) &_ggraph_partitionTree, 4}, + {"_ggraph_pathAttr", (DL_FUNC) &_ggraph_pathAttr, 6}, + {"_ggraph_splitTreemap", (DL_FUNC) &_ggraph_splitTreemap, 5}, + {"_ggraph_unrooted", (DL_FUNC) &_ggraph_unrooted, 7}, + {NULL, NULL, 0} +}; +} + +extern "C" attribute_visible void R_init_ggraph(DllInfo* dll){ + R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); + R_useDynamicSymbols(dll, FALSE); + R_forceSymbols(dll, TRUE); +} diff --git a/src/dendrogram.cpp b/src/dendrogram.cpp index cc66bd9a..0fadc4f2 100644 --- a/src/dendrogram.cpp +++ b/src/dendrogram.cpp @@ -1,25 +1,27 @@ -#include -using namespace Rcpp; +#include +#include +#include +#include -double max_leaf(NumericVector& x, LogicalVector& leaf) { +double max_leaf(cpp11::doubles& x, cpp11::logicals& leaf) { double max = NA_REAL; - for (int i = 0; i < x.length(); ++i) { - if (leaf[i] && !NumericVector::is_na(x[i]) && (R_IsNA(max) || max < x[i])) { + for (R_xlen_t i = 0; i < x.size(); ++i) { + if (leaf[i] && !cpp11::is_na(x[i]) && (R_IsNA(max) || max < x[i])) { max = x[i]; } } return max; } -void recurse_dendrogram(ListOf& graph, int node, NumericVector& x, NumericVector& y, LogicalVector& leaf, double offset, bool repel, double pad, double ratio) { - if (graph[node].length() == 0) { +void recurse_dendrogram(cpp11::list_of& graph, int node, cpp11::writable::doubles& x, cpp11::doubles& y, cpp11::logicals& leaf, double offset, bool repel, double pad, double ratio) { + if (graph[node].size() == 0) { x[node] = offset; } else { double min_x = NA_REAL; double max_x = NA_REAL; - for (int i = 0; i < graph[node].length(); ++i) { + for (int i = 0; i < graph[node].size(); ++i) { int child = graph[node][i] - 1; - if (NumericVector::is_na(x[child])) { + if (R_IsNA(x[child])) { recurse_dendrogram(graph, child, x, y, leaf, offset, repel, pad, ratio); offset = max_leaf(x, leaf); if (repel) { @@ -35,10 +37,11 @@ void recurse_dendrogram(ListOf& graph, int node, NumericVector& x } } -//[[Rcpp::export]] -NumericVector dendrogram_spread(ListOf graph, IntegerVector starts, NumericVector y, LogicalVector leaf, bool repel, double pad, double ratio) { - NumericVector x_loc(y.length(), NA_REAL); - for (int i = 0; i < starts.length(); ++i) { +[[cpp11::register]] +cpp11::writable::doubles dendrogram_spread(cpp11::list_of graph, cpp11::integers starts, cpp11::doubles y, cpp11::logicals leaf, bool repel, double pad, double ratio) { + cpp11::writable::doubles x_loc(y.size()); + std::fill(x_loc.begin(), x_loc.end(), NA_REAL); + for (R_xlen_t i = 0; i < starts.size(); ++i) { recurse_dendrogram(graph, starts[i] - 1, x_loc, y, leaf, 0.0, repel, pad, ratio); } return x_loc; diff --git a/src/forceBundle.cpp b/src/forceBundle.cpp index 09a84cef..2fcf4736 100644 --- a/src/forceBundle.cpp +++ b/src/forceBundle.cpp @@ -2,320 +2,329 @@ // implements Holten, Danny, and Jarke J. Van Wijk. "Force‐Directed Edge // Bundling for Graph Visualization." Computer Graphics Forum (Blackwell // Publishing Ltd) 28, no. 3 (2009): 983-990. -#include -using namespace Rcpp; -double euclidean_distance(NumericVector P, NumericVector Q) { - return sqrt((P[0] - Q[0]) * (P[0] - Q[0]) + (P[1] - Q[1]) * (P[1] - Q[1])); -} +#include +#include +#include +#include +#include + +#include + +using namespace cpp11::literals; + +class Point { +public: + double x; + double y; + + Point() : x(0.0), y(0.0) {}; + Point(double _x, double _y) : x(_x), y(_y) {}; + Point(const Point& p) : x(p.x), y(p.y) {}; + + Point operator+(const Point& p) const { + return {x + p.x, y + p.y}; + }; + + Point& operator+=(const Point& p) { + x += p.x; + y += p.y; + return *this; + }; + + Point operator-(const Point& p) const { + return {x - p.x, y - p.y}; + }; + + Point& operator-=(const Point& p) { + x -= p.x; + y -= p.y; + return *this; + }; + + Point operator*(double fac) const { + return {x * fac, y * fac}; + }; + + Point& operator*=(double fac) { + x *= fac; + y *= fac; + return *this; + }; + + double operator*(const Point& p) const { + return dot(p); + }; + + Point operator/(double fac) const { + return {x / fac, y / fac}; + }; + + Point& operator/=(double fac) { + x /= fac; + y /= fac; + return *this; + }; + + bool operator==(const Point& p) const { + return x == p.x && y == p.y; + }; + + bool operator!=(const Point& p) const { + return x != p.x || y != p.y; + }; + + double distance_to(const Point& p, double eps = 0) const { + double dx = x - p.x; + double dy = y - p.y; + if (std::abs(dx) < eps && std::abs(dy) < eps) return eps; + + return std::sqrt(dx * dx + dy * dy); + } -double edge_length(NumericVector P, NumericVector Q, double eps) { - if ((std::abs(P[0] - Q[0]) < eps) && (std::abs(P[1] - Q[1]) < eps)) { - return eps; - } else { - return euclidean_distance(P, Q); + double dot(const Point& p) const { + return x * p.x + y * p.y; + } +}; +class Segment { +public: + Point a; + Point b; + + Segment() : a(), b() {}; + Segment(Point _a, Point _b) : a(_a), b(_b) {}; + Segment(double x0, double y0, double x1, double y1) : a(x0, y0), b(x1, y1) {}; + Segment(const Segment& s) : a(s.a), b(s.b) {}; + + double length(double eps = 0.0) const { + return a.distance_to(b, eps); } -} -double vector_dot_product(NumericVector P, NumericVector Q) { - return P[0] * Q[0] + P[1] * Q[1]; -} + Point as_vec() const { + return b - a; + } -NumericVector edge_as_vector(NumericVector P) { - NumericVector vec = {P[2] - P[0], P[3] - P[1]}; - return vec; -} + Point project(const Point& p, double eps = 0.0) const { + Point vec = as_vec(); -NumericVector project_point_on_line(NumericVector p, NumericVector Q) { - double Q_target_x = Q[2]; - double Q_source_x = Q[0]; - double Q_target_y = Q[3]; - double Q_source_y = Q[1]; - double p_x = p[0]; - double p_y = p[1]; + double l2 = vec * vec; + double u = ((p.x - a.x) * vec.x + (p.y - a.y) * vec.y) / l2; - double L = sqrt((Q_target_x - Q_source_x) * (Q_target_x - Q_source_x) + - (Q_target_y - Q_source_y) * (Q_target_y - Q_source_y)); - double r = ((Q_source_y - p_y) * (Q_source_y - Q_target_y) - - (Q_source_x - p_x) * (Q_target_x - Q_source_x)) / - (L * L); + return a + vec * u; + } - NumericVector vec = {(Q_source_x + r * (Q_target_x - Q_source_x)), - (Q_source_y + r * (Q_target_y - Q_source_y))}; + Segment project(const Segment& s, double eps = 0.0) const { + return {project(s.a, eps), project(s.b, eps)}; + } - return vec; -} + Point midpoint() const { + return (a + b) / 2.0; + } -double edge_visibility(NumericVector P, NumericVector Q) { - NumericVector qs = {Q[0], Q[1]}; - NumericVector qt = {Q[2], Q[3]}; + bool are_compatible(const Segment& Q, double compatibility_threshold, double eps = 0.0) const { + return compatibility_score(Q, eps) >= compatibility_threshold; + } + +private: + double visibility(const Segment& s, double eps = 0.0) const { + Segment proj_s = project(s, eps); + return std::max(1.0 - 2.0 * midpoint().distance_to(proj_s.midpoint(), eps) / proj_s.length(eps), 0.0); + } + double angle_comp(const Segment& Q, double eps = 0.0) const { + double dot_PQ = as_vec() * Q.as_vec(); + double euc_PQ = length(eps) * Q.length(eps); + return std::abs(dot_PQ / euc_PQ); + } + double scale_comp(const Segment& Q, double eps = 0.0) const { + double euc_P = length(eps); + double euc_Q = Q.length(eps); - NumericVector I0 = project_point_on_line(qs, P); - NumericVector I1 = project_point_on_line(qt, P); + double lavg = (euc_P + euc_Q) / 2.0; + return 2.0 / (lavg / std::min(euc_P, euc_Q) + std::max(euc_P, euc_Q) / lavg); + } + double position_comp(const Segment& Q, double eps = 0.0) const { + double euc_P = length(eps); + double euc_Q = Q.length(eps); - NumericVector midI = {(I0[0] + I1[0]) / 2.0, (I0[1] + I1[1]) / 2.0}; - NumericVector midP = {(P[0] + P[2]) / 2.0, (P[1] + P[3]) / 2.0}; + double lavg = (euc_P + euc_Q) / 2.0; - double tmp = - 1.0 - 2.0 * euclidean_distance(midP, midI) / euclidean_distance(I0, I1); - if (tmp > 0) { - return tmp; - } else { - return 0; + double euc_mid = midpoint().distance_to(Q.midpoint(), eps); + return lavg / (lavg + euc_mid); } -} + double visibility_comp(const Segment& Q, double eps = 0.0) const { + return std::min(visibility(Q, eps), Q.visibility(*this, eps)); + } + double compatibility_score(const Segment& Q, double eps = 0.0) const { + return angle_comp(Q, eps) * scale_comp(Q, eps) * position_comp(Q, eps) * visibility_comp(Q, eps); + } +}; + +typedef std::vector Path; + -double compute_divided_edge_length(NumericMatrix emat) { - int segments = emat.rows() - 1; +double compute_divided_edge_length(Path& edge) { + int segments = edge.size() - 1; double length = 0.0; for (int i = 0; i < segments; ++i) { - double segment_length = euclidean_distance(emat(i, _), emat(i + 1, _)); - length += segment_length; + length += edge[i].distance_to(edge[i + 1]); } return length; } -List update_edge_divisions(List elist, int P) { - for (int e_idx = 0; e_idx < elist.length(); ++e_idx) { - NumericMatrix emat = elist[e_idx]; +void update_edge_divisions(std::vector& elist, int P) { + for (size_t e_idx = 0; e_idx < elist.size(); ++e_idx) { if (P == 1) { - NumericMatrix emat_new(3, 2); - emat_new(0, 0) = emat(0, 0); - emat_new(0, 1) = emat(0, 1); - emat_new(1, 0) = (emat(0, 0) + emat(1, 0)) / 2.0; - emat_new(1, 1) = (emat(0, 1) + emat(1, 1)) / 2.0; - emat_new(2, 0) = emat(1, 0); - emat_new(2, 1) = emat(1, 1); - elist[e_idx] = emat_new; + elist[e_idx].insert(elist[e_idx].begin() + 1, Segment(elist[e_idx][0], elist[e_idx][1]).midpoint()); } else { - double divided_edge_length = compute_divided_edge_length(emat); - double segment_length = divided_edge_length / (P + 1); - double current_segment_length = segment_length; - NumericMatrix emat_new(P + 2, 2); - emat_new(0, _) = emat(0, _); - emat_new((emat_new.rows() - 1), _) = emat((emat.rows() - 1), _); - int cur = 1; - for (int i = 1; i < emat.rows(); ++i) { - double old_segment_length = - euclidean_distance(emat(i - 1, _), emat(i, _)); - while (old_segment_length > current_segment_length) { - double percent_position = current_segment_length / old_segment_length; - double new_subdivision_point_x = emat(i - 1, 0); - double new_subdivision_point_y = emat(i - 1, 1); - - new_subdivision_point_x += - percent_position * (emat(i, 0) - emat(i - 1, 0)); - new_subdivision_point_y += - percent_position * (emat(i, 1) - emat(i - 1, 1)); - - emat_new(cur, 0) = new_subdivision_point_x; - emat_new(cur, 1) = new_subdivision_point_y; - cur += 1; - old_segment_length = old_segment_length - current_segment_length; - current_segment_length = segment_length; + Path edge = elist[e_idx]; + double current_edge_length = compute_divided_edge_length(edge); + double new_segment_length = current_edge_length / (P + 1); + double current_segment_length = new_segment_length; + elist[e_idx].clear(); + elist[e_idx].reserve(P + 2); + elist[e_idx].push_back(edge[0]); + for (size_t i = 1; i < edge.size(); ++i) { + Point& start_point = edge[i - 1]; + Point vec = edge[i] - start_point; + double segment_length = start_point.distance_to(edge[i]); + while (segment_length > current_segment_length) { + double percent_position = current_segment_length / segment_length; + + elist[e_idx].push_back(start_point + vec * percent_position); + + current_segment_length += new_segment_length; } - current_segment_length -= old_segment_length; + current_segment_length -= segment_length; } - elist[e_idx] = emat_new; + while (elist[e_idx].size() > P + 1) { + elist[e_idx].pop_back(); + } + elist[e_idx].push_back(edge.back()); } } - - return elist; -} - -double angle_compatibility(NumericVector P, NumericVector Q) { - NumericVector P_source = {P[0], P[1]}; - NumericVector P_target = {P[2], P[3]}; - NumericVector Q_source = {Q[0], Q[1]}; - NumericVector Q_target = {Q[2], Q[3]}; - - double dot_PQ = vector_dot_product(edge_as_vector(P), edge_as_vector(Q)); - double euc_PQ = euclidean_distance(P_source, P_target) * - euclidean_distance(Q_source, Q_target); - double frac_PQ = dot_PQ / euc_PQ; - return std::abs(frac_PQ); } -double scale_compatibility(NumericVector P, NumericVector Q) { - NumericVector P_source = {P[0], P[1]}; - NumericVector P_target = {P[2], P[3]}; - NumericVector Q_source = {Q[0], Q[1]}; - NumericVector Q_target = {Q[2], Q[3]}; - - double euc_P = euclidean_distance(P_source, P_target); - double euc_Q = euclidean_distance(Q_source, Q_target); - - double lavg = (euc_P + euc_Q) / 2.0; - return 2.0 / (lavg / std::min(euc_P, euc_Q) + std::max(euc_P, euc_Q) / lavg); -} - -double position_compatibility(NumericVector P, NumericVector Q) { - NumericVector P_source = {P[0], P[1]}; - NumericVector P_target = {P[2], P[3]}; - NumericVector Q_source = {Q[0], Q[1]}; - NumericVector Q_target = {Q[2], Q[3]}; - - double euc_P = euclidean_distance(P_source, P_target); - double euc_Q = euclidean_distance(Q_source, Q_target); - - double lavg = (euc_P + euc_Q) / 2.0; - - NumericVector midP = {(P_source[0] + P_target[0]) / 2.0, - (P_source[1] + P_target[1]) / 2.0}; - - NumericVector midQ = {(Q_source[0] + Q_target[0]) / 2.0, - (Q_source[1] + Q_target[1]) / 2.0}; - - double euc_mid = euclidean_distance(midP, midQ); - return lavg / (lavg + euc_mid); -} - -double visibility_compatibility(NumericVector P, NumericVector Q) { - return std::min(edge_visibility(P, Q), edge_visibility(Q, P)); -} - -double compatibility_score(NumericVector P, NumericVector Q) { - return angle_compatibility(P, Q) * scale_compatibility(P, Q) * - position_compatibility(P, Q) * visibility_compatibility(P, Q); -} - -bool are_compatible(NumericVector P, NumericVector Q, - double compatibility_threshold) { - return compatibility_score(P, Q) >= compatibility_threshold; -} - -List compute_compatibility_lists(NumericMatrix edges_xy, - double compatibility_threshold) { - int m = edges_xy.rows(); - List elist_comp(m); - for (int e = 0; e < (m - 1); ++e) { - NumericVector P = edges_xy(e, _); - for (int oe = (e + 1); oe < m; ++oe) { - NumericVector Q = edges_xy(oe, _); - if (are_compatible(P, Q, compatibility_threshold)) { - if (elist_comp[e] == R_NilValue) { - IntegerVector ecomp = {oe}; - elist_comp[e] = ecomp; - } else { - IntegerVector ecomp = elist_comp[e]; - ecomp.push_back(oe); - elist_comp[e] = ecomp; - } - if (elist_comp[oe] == R_NilValue) { - IntegerVector oecomp = {e}; - elist_comp[oe] = oecomp; - } else { - IntegerVector oecomp = elist_comp[oe]; - oecomp.push_back(e); - elist_comp[oe] = oecomp; - } +std::vector< std::vector > compute_compatibility_lists(std::vector& edges, double compatibility_threshold) { + size_t m = edges.size(); + std::vector< std::vector > comp(m); + for (size_t e = 0; e < (m - 1); ++e) { + Segment P(edges[e][0], edges[e][1]); + for (size_t oe = (e + 1); oe < m; ++oe) { + Segment Q(edges[oe][0], edges[oe][1]); + if (P.are_compatible(Q, compatibility_threshold)) { + comp[e].push_back(oe); + comp[oe].push_back(e); } } } - return elist_comp; + return comp; } -NumericVector apply_spring_force(List elist, int e_idx, int i, double kP) { - NumericMatrix emat = elist[e_idx]; - NumericVector prec = emat(i - 1, _); - NumericVector succ = emat(i + 1, _); - NumericVector crnt = emat(i, _); - - double x = prec[0] - crnt[0] + succ[0] - crnt[0]; - double y = prec[1] - crnt[1] + succ[1] - crnt[1]; - - x *= kP; - y *= kP; +Point apply_spring_force(const std::vector& edges, int e_idx, int i, double kP) { + const Path& edge = edges[e_idx]; - return {x, y}; + return (edge[i - 1] + edge[i + 1] - edge[i] * 2) * kP; } -NumericVector apply_electrostatic_force(List elist, List elist_comp, int e_idx, - int i, double eps) { - NumericVector sum_of_forces(2); - if (elist_comp[e_idx] == R_NilValue) { +Point apply_electrostatic_force(const std::vector& edges, + const std::vector< std::vector >& comp, + int e_idx, int i, double eps) { + Point sum_of_forces; + if (comp[e_idx].empty()) { return sum_of_forces; } - IntegerVector ecomps = elist_comp[e_idx]; - NumericMatrix emat = elist[e_idx]; - - for (int oe = 0; oe < ecomps.length(); ++oe) { - NumericMatrix oemat = elist[ecomps[oe]]; - NumericVector force = {oemat(i, 0) - emat(i, 0), oemat(i, 1) - emat(i, 1)}; - if ((std::abs(force[0]) > eps) || (std::abs(force[1]) > eps)) { - double euc = euclidean_distance(oemat(i, _), emat(i, _)); + const std::vector& compatible_edges = comp[e_idx]; + const Path& edge = edges[e_idx]; + + for (size_t oe = 0; oe < compatible_edges.size(); ++oe) { + const Path& edge2 = edges[compatible_edges[oe]]; + Point force = edge2[i] - edge[i]; + if ((std::abs(force.x) > eps) || (std::abs(force.y) > eps)) { + double euc = edge2[i].distance_to(edge[i]); double diff = std::pow(euc, -1.0); - sum_of_forces[0] += force[0] * diff; - sum_of_forces[1] += force[1] * diff; + sum_of_forces += force * diff; } } return sum_of_forces; } -NumericMatrix apply_resulting_forces_on_subdivision_points(List elist, - List elist_comp, - int e_idx, int P, - double S, double K, - double eps) { - NumericMatrix emat = elist[e_idx]; +std::vector apply_resulting_forces_on_subdivision_points(const std::vector& edges, + const std::vector< std::vector >& comp, + int e_idx, int P, + double S, double K, + double eps) { + const Path& edge = edges[e_idx]; - double kP = K / (edge_length(emat(0, _), emat(P + 1, _), eps) * (P + 1)); + double kP = K / (edge[0].distance_to(edge[P + 1], eps) * (P + 1)); - NumericMatrix resulting_forces_for_subdivision_points(P + 2, 2); + std::vector resulting_forces_for_subdivision_points(P + 2); for (int i = 1; i < (P + 1); ++i) { - NumericMatrix resulting_force(2); - NumericVector spring_force = apply_spring_force(elist, e_idx, i, kP); + Point spring_force = apply_spring_force(edges, e_idx, i, kP); - NumericVector electrostatic_force = - apply_electrostatic_force(elist, elist_comp, e_idx, i, eps); + Point electrostatic_force = apply_electrostatic_force(edges, comp, e_idx, i, eps); - resulting_force[0] = S * (spring_force[0] + electrostatic_force[0]); - resulting_force[1] = S * (spring_force[1] + electrostatic_force[1]); - - resulting_forces_for_subdivision_points(i, _) = resulting_force; + resulting_forces_for_subdivision_points[i] = (spring_force + electrostatic_force) * S; } return resulting_forces_for_subdivision_points; } -// [[Rcpp::export]] -List force_bundle_iter(NumericMatrix edges_xy, List elist, double K, int C, + +[[cpp11::register]] +cpp11::writable::data_frame force_bundle_iter(cpp11::doubles_matrix<> edges_xy, double K, int C, int P, int P_rate, double S, int I, double I_rate, double compatibility_threshold, double eps) { - int m = edges_xy.rows(); + R_xlen_t m = edges_xy.nrow(); // first division - - elist = update_edge_divisions(elist, P); + std::vector edges(m); + for (R_xlen_t i = 0; i < m; ++i) { + edges[i].push_back(Point(edges_xy(i, 0), edges_xy(i, 1))); + edges[i].push_back(Point(edges_xy(i, 2), edges_xy(i, 3))); + } // compute compatibility list - List elist_comp = - compute_compatibility_lists(edges_xy, compatibility_threshold); + auto comp = compute_compatibility_lists(edges, compatibility_threshold); + + update_edge_divisions(edges, P); // main loop for (int cycle = 0; cycle < C; ++cycle) { for (int iteration = 0; iteration < I; ++iteration) { - List forces(m); - for (int e = 0; e < m; ++e) { - forces[e] = apply_resulting_forces_on_subdivision_points( - elist, elist_comp, e, P, S, K, eps); + std::vector< std::vector > forces(m); + for (R_xlen_t e = 0; e < m; ++e) { + forces[e] = apply_resulting_forces_on_subdivision_points(edges, comp, e, P, S, K, eps); } for (int e = 0; e < m; ++e) { - NumericMatrix emat = elist[e]; - NumericMatrix fmat = forces[e]; for (int i = 0; i < (P + 1); ++i) { - emat(i, 0) += fmat(i, 0); - emat(i, 1) += fmat(i, 1); + edges[e][i] += forces[e][i]; } - elist[e] = emat; } } if (cycle != (C - 1)) { S = S / 2.0; P = P * P_rate; I = I * I_rate; - elist = update_edge_divisions(elist, P); + update_edge_divisions(edges, P); + } + } + + cpp11::writable::doubles x; + x.reserve(m * edges[0].size()); + cpp11::writable::doubles y; + y.reserve(m * edges[0].size()); + cpp11::writable::integers id; + id.reserve(m * edges[0].size()); + for (size_t i = 0; i < edges.size(); ++i) { + for (size_t j = 0; j < edges[i].size(); ++j) { + x.push_back(edges[i][j].x); + y.push_back(edges[i][j].y); + id.push_back(i + 1); } } - return elist; + return cpp11::writable::data_frame({ + "x"_nm = x, + "y"_nm = y, + "group"_nm = id + }); } diff --git a/src/hTree.cpp b/src/hTree.cpp index 0e6d2a18..d7f5b21d 100644 --- a/src/hTree.cpp +++ b/src/hTree.cpp @@ -1,6 +1,10 @@ -#include #include "nodes.h" -using namespace Rcpp; + +#include +#include +#include + +#include void hLayout(Node* node, double x, double y, bool horizontal, double length) { Rectangle r = {x, y, 0.0, 0.0}; @@ -13,12 +17,12 @@ void hLayout(Node* node, double x, double y, bool horizontal, double length) { } } -//[[Rcpp::export]] -NumericMatrix hTree(IntegerVector parent, IntegerVector order) { - NumericMatrix pos(parent.size(), 2); +[[cpp11::register]] +cpp11::writable::doubles_matrix<> hTree(cpp11::integers parent, cpp11::integers order) { + cpp11::writable::doubles_matrix<> pos(parent.size(), 2); unsigned int i; - std::vector nodes = createHierarchy(as< std::vector >(parent), as< std::vector >(order)); + std::vector nodes = createHierarchy(parent, order); for (i = 0; i < nodes.size(); ++i) { nodes[i]->sortChildren(); diff --git a/src/iciclePlot.cpp b/src/iciclePlot.cpp index 5a233f42..0c01b15a 100644 --- a/src/iciclePlot.cpp +++ b/src/iciclePlot.cpp @@ -1,6 +1,10 @@ -#include #include "nodes.h" -using namespace Rcpp; + +#include +#include +#include + +#include void icicleLayout(Node* node, double x, double y) { Rectangle r = {x, y, node->weight(), node->height()}; @@ -15,12 +19,12 @@ void icicleLayout(Node* node, double x, double y) { } } -//[[Rcpp::export]] -NumericMatrix partitionTree(IntegerVector parent, IntegerVector order, NumericVector weight, NumericVector height) { - NumericMatrix rect(parent.size(), 4); +[[cpp11::register]] +cpp11::writable::doubles_matrix<> partitionTree(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, cpp11::doubles height) { + cpp11::writable::doubles_matrix<> rect(parent.size(), 4); unsigned int i; - std::vector nodes = createHierarchy(as< std::vector >(parent), as< std::vector >(order), as< std::vector >(weight), as< std::vector >(height)); + std::vector nodes = createHierarchy(parent, order, weight, height); for (i = 0; i < nodes.size(); ++i) { nodes[i]->sortChildren(); diff --git a/src/lineCutter.cpp b/src/lineCutter.cpp index e5cd590c..506273d9 100644 --- a/src/lineCutter.cpp +++ b/src/lineCutter.cpp @@ -1,5 +1,9 @@ -#include -using namespace Rcpp; +#include +#include +#include +#include + +using namespace cpp11::literals; double copy_sign(double from, double to) { if (from > 0) { @@ -105,7 +109,7 @@ bool inside_ellipsis(Point p, Point p0, double width, double height) { double pY = p.y - p0.y; return (pX * pX) / (width * width) + (pY * pY) / (height * height) < 1; } -void capRectStart(NumericVector &x, NumericVector &y, int from, int to, double width, double height) { +void capRectStart(cpp11::writable::doubles &x, cpp11::writable::doubles &y, int from, int to, double width, double height) { int i; Point p; Point p0 = point(x[from], y[from]); @@ -127,7 +131,7 @@ void capRectStart(NumericVector &x, NumericVector &y, int from, int to, double w } } } -void capRectEnd(NumericVector &x, NumericVector &y, int from, int to, double width, double height) { +void capRectEnd(cpp11::writable::doubles &x, cpp11::writable::doubles &y, int from, int to, double width, double height) { int i = to - 1; Point p; Point p0 = point(x[i], y[i]); @@ -149,7 +153,7 @@ void capRectEnd(NumericVector &x, NumericVector &y, int from, int to, double wid } } } -void capEllipStart(NumericVector &x, NumericVector &y, int from, int to, double width, double height) { +void capEllipStart(cpp11::writable::doubles &x, cpp11::writable::doubles &y, int from, int to, double width, double height) { int i; Point p; Point p0 = point(x[from], y[from]); @@ -171,7 +175,7 @@ void capEllipStart(NumericVector &x, NumericVector &y, int from, int to, double } } } -void capEllipEnd(NumericVector &x, NumericVector &y, int from, int to, double width, double height) { +void capEllipEnd(cpp11::writable::doubles &x, cpp11::writable::doubles &y, int from, int to, double width, double height) { int i = to - 1; Point p; Point p0 = point(x[i], y[i]); @@ -194,10 +198,10 @@ void capEllipEnd(NumericVector &x, NumericVector &y, int from, int to, double wi } } -//[[Rcpp::export]] -List cut_lines(NumericVector x, NumericVector y, IntegerVector id, NumericVector start_width, NumericVector start_height, NumericVector end_width, NumericVector end_height, CharacterVector start_type, CharacterVector end_type) { - NumericVector new_x = clone(x); - NumericVector new_y = clone(y); +[[cpp11::register]] +cpp11::writable::data_frame cut_lines(cpp11::doubles x, cpp11::doubles y, cpp11::integers id, cpp11::doubles start_width, cpp11::doubles start_height, cpp11::doubles end_width, cpp11::doubles end_height, cpp11::strings start_type, cpp11::strings end_type) { + cpp11::writable::doubles new_x(x); + cpp11::writable::doubles new_y(y); int i, j, group, group_ind; group_ind = j = 0; group = id[group_ind]; @@ -238,5 +242,8 @@ List cut_lines(NumericVector x, NumericVector y, IntegerVector id, NumericVector } } - return List::create(Named("x") = new_x, Named("y") = new_y); + return cpp11::writable::data_frame({ + "x"_nm = x, + "y"_nm = y + }); } diff --git a/src/nodes.cpp b/src/nodes.cpp index c5c0db1b..3f1d3d1d 100644 --- a/src/nodes.cpp +++ b/src/nodes.cpp @@ -1,40 +1,42 @@ #include "nodes.h" -std::vector createHierarchy(std::vector parent, std::vector order, std::vector weight) { + +#include + +std::vector createHierarchy(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight) { std::vector nodes; - unsigned int i; - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { Node* node = new Node(i, order[i], weight[i]); nodes.push_back(node); } - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { if (parent[i] >= 0) { nodes[parent[i]]->addNode(nodes[i]); } } return nodes; } -std::vector createHierarchy(std::vector parent, std::vector order, std::vector weight, std::vector height) { + +std::vector createHierarchy(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, cpp11::doubles height) { std::vector nodes; - unsigned int i; - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { Node* node = new Node(i, order[i], weight[i], height[i]); nodes.push_back(node); } - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { if (parent[i] >= 0) { nodes[parent[i]]->addNode(nodes[i]); } } return nodes; } -std::vector createHierarchy(std::vector parent, std::vector order) { + +std::vector createHierarchy(cpp11::integers parent, cpp11::integers order) { std::vector nodes; - unsigned int i; - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { Node* node = new Node(i, order[i], 0.0); nodes.push_back(node); } - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { if (parent[i] >= 0) { nodes[parent[i]]->addNode(nodes[i]); } @@ -42,14 +44,13 @@ std::vector createHierarchy(std::vector parent, std::vector ord return nodes; } -std::vector createUnrooted(std::vector parent, std::vector order, std::vector length) { +std::vector createUnrooted(cpp11::integers parent, cpp11::integers order, cpp11::doubles length) { std::vector nodes; - unsigned int i; - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { Node* node = new Node(i, order[i], 1, length[i]); nodes.push_back(node); } - for (i = 0; i < parent.size(); ++i) { + for (R_xlen_t i = 0; i < parent.size(); ++i) { if (parent[i] >= 0) { nodes[parent[i]]->addNode(nodes[i]); } diff --git a/src/nodes.h b/src/nodes.h index 51ac167c..708be37b 100644 --- a/src/nodes.h +++ b/src/nodes.h @@ -1,5 +1,7 @@ -#include -using namespace Rcpp; +#pragma once +#include +#include +#include struct Rectangle { double x; @@ -195,7 +197,8 @@ class Node { Rectangle bounds; }; -std::vector createHierarchy(std::vector parent, std::vector order, std::vector weight); -std::vector createHierarchy(std::vector parent, std::vector order, std::vector weight, std::vector height); -std::vector createHierarchy(std::vector parent, std::vector order); -std::vector createUnrooted(std::vector parent, std::vector order, std::vector length); + +std::vector createHierarchy(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight); +std::vector createHierarchy(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, cpp11::doubles height); +std::vector createHierarchy(cpp11::integers parent, cpp11::integers order); +std::vector createUnrooted(cpp11::integers parent, cpp11::integers order, cpp11::doubles length); diff --git a/src/pathAttr.cpp b/src/pathAttr.cpp index aa6e1f87..1923a874 100644 --- a/src/pathAttr.cpp +++ b/src/pathAttr.cpp @@ -1,37 +1,37 @@ -#include +#include +#include +#include +#include +#include +#include -using namespace Rcpp; +using namespace cpp11::literals; -//[[Rcpp::export]] -DataFrame pathAttr(DataFrame paths, int ngroups) { - LogicalVector solid(ngroups, true); - LogicalVector constant(ngroups, true); +[[cpp11::register]] +cpp11::writable::data_frame pathAttr(cpp11::integers group, cpp11::doubles alpha, + cpp11::doubles width, cpp11::strings lty, + cpp11::strings colour, int ngroups) { + cpp11::writable::logicals solid(ngroups); + std::fill(solid.begin(), solid.end(), true); + cpp11::writable::logicals constant(ngroups); + std::fill(constant.begin(), constant.end(), true); int currentGroup, currentIndex, i; - IntegerVector group = paths["group"]; - NumericVector alpha = paths["edge_alpha"]; - LogicalVector alpha_na = is_na(alpha); - NumericVector width = paths["edge_width"]; - LogicalVector width_na = is_na(width); - CharacterVector lty = paths["edge_linetype"]; - LogicalVector lty_na = is_na(lty); - CharacterVector colour = paths["edge_colour"]; - LogicalVector colour_na = is_na(colour); currentGroup = group[0]; currentIndex = 0; for (i = 1; i < group.size(); ++i) { if (group[i] == currentGroup) { - if (solid[currentIndex]) { + if (solid[currentIndex] == TRUE) { solid[currentIndex] = lty[i] == "solid" && lty[i] == lty[i-1]; } - if (constant[currentIndex]) { + if (constant[currentIndex] == TRUE) { constant[currentIndex] = - ((alpha[i] == alpha[i-1]) || (alpha_na[i] && alpha_na[i-1])) && - ((width[i] == width[i-1]) || (width_na[i] && width_na[i-1])) && - ((lty[i] == lty[i-1]) || (lty_na[i] && lty_na[i-1])) && - ((colour[i] == colour[i-1]) || (colour_na[i] && colour_na[i-1])); + ((alpha[i] == alpha[i-1]) || (cpp11::is_na(alpha[i]) && cpp11::is_na(alpha[i-1]))) && + ((width[i] == width[i-1]) || (cpp11::is_na(width[i]) && cpp11::is_na(width[i-1]))) && + ((lty[i] == lty[i-1]) || (cpp11::is_na(lty[i]) && cpp11::is_na(lty[i-1]))) && + ((colour[i] == colour[i-1]) || (cpp11::is_na(colour[i]) && cpp11::is_na(colour[i-1]))); } } else { currentGroup = group[i]; @@ -39,8 +39,8 @@ DataFrame pathAttr(DataFrame paths, int ngroups) { } } - return DataFrame::create( - Named("solid") = solid, - Named("constant") = constant - ); + return cpp11::writable::data_frame({ + "solid"_nm = solid, + "constant"_nm = constant + }); } diff --git a/src/treemap.cpp b/src/treemap.cpp index 63a7e334..6e4e1689 100644 --- a/src/treemap.cpp +++ b/src/treemap.cpp @@ -1,6 +1,10 @@ -#include #include "nodes.h" -using namespace Rcpp; + +#include +#include +#include + +#include double w(std::vector& nodes) { double w = 0; @@ -70,12 +74,12 @@ void splitLayout(std::vector items, Rectangle r) { } } -//[[Rcpp::export]] -NumericMatrix splitTreemap(IntegerVector parent, IntegerVector order, NumericVector weight, double width, double height) { - NumericMatrix rect(parent.size(), 4); +[[cpp11::register]] +cpp11::writable::doubles_matrix<> splitTreemap(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, double width, double height) { + cpp11::writable::doubles_matrix<> rect(parent.size(), 4); unsigned int i; - std::vector nodes = createHierarchy(as< std::vector >(parent), as< std::vector >(order), as< std::vector >(weight)); + std::vector nodes = createHierarchy(parent, order, weight); for (i = 0; i < nodes.size(); ++i) { nodes[i]->sortChildren(); diff --git a/src/unrooted.cpp b/src/unrooted.cpp index 7e4bdf59..2a748701 100644 --- a/src/unrooted.cpp +++ b/src/unrooted.cpp @@ -1,10 +1,12 @@ -#include #include "nodes.h" -using namespace Rcpp; -const double PI2 = 6.28318; +#include +#include +#include +#include +const double PI2 = 6.28318; void equalAngle(Node* node, double start, double angle) { if (node->leaf()) return; @@ -90,11 +92,11 @@ double equalDaylight(Node* node, double rotation_mod) { return daylight_change / leafs.size(); } -//[[Rcpp::export]] -NumericMatrix unrooted(IntegerVector parent, IntegerVector order, NumericVector length, bool daylight, double tol, double rotation_mod, int maxiter) { - NumericMatrix rect(parent.size(), 2); +[[cpp11::register]] +cpp11::writable::doubles_matrix<> unrooted(cpp11::integers parent, cpp11::integers order, cpp11::doubles length, bool daylight, double tol, double rotation_mod, int maxiter) { + cpp11::writable::doubles_matrix<> rect(parent.size(), 2); - std::vector nodes = createUnrooted(as< std::vector >(parent), as< std::vector >(order), as< std::vector >(length)); + std::vector nodes = createUnrooted(parent, order, length); Node* startNode = nodes[0]->getRoot(); std::vector children = startNode->getChildren(); for (unsigned int i = 0; i < children.size(); ++i) {