Skip to content

Commit 6f1f8d8

Browse files
committed
Fix #308 Provide concaveman as C++ code
1 parent 5d70067 commit 6f1f8d8

File tree

10 files changed

+934
-12
lines changed

10 files changed

+934
-12
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ LinkingTo: Rcpp, RcppEigen
4545
RoxygenNote: 7.2.3
4646
Suggests:
4747
sessioninfo,
48-
concaveman,
4948
deldir,
5049
latex2exp,
5150
reshape2,
@@ -64,6 +63,7 @@ Collate:
6463
'bspline.R'
6564
'bspline_closed.R'
6665
'circle.R'
66+
'concaveman.R'
6767
'diagonal.R'
6868
'diagonal_wide.R'
6969
'ellipse.R'

LICENSE.note

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--------------------------------------------------------------------------------
2+
The concaveman.h file is redistributed with the following license
3+
4+
BSD 2-Clause License
5+
6+
Copyright (c) 2019, sadaszewski
7+
All rights reserved.
8+
9+
Redistribution and use in source and binary forms, with or without
10+
modification, are permitted provided that the following conditions are met:
11+
12+
1. Redistributions of source code must retain the above copyright notice, this
13+
list of conditions and the following disclaimer.
14+
15+
2. Redistributions in binary form must reproduce the above copyright notice,
16+
this list of conditions and the following disclaimer in the documentation
17+
and/or other materials provided with the distribution.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
30+
--------------------------------------------------------------------------------

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# ggforce (development version)
22

33
* Fixed a bug that would cause reordering of data in some geoms (#314)
4+
* The concaveman package is no longer a dependency for `geom_mark_hull()` (#308)
45

56
# ggforce 0.4.1
67

R/RcppExports.R

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ getBeziers <- function(x, y, id, detail) {
1717
.Call('_ggforce_getBeziers', PACKAGE = 'ggforce', x, y, id, detail)
1818
}
1919

20+
concaveman_c <- function(p, h, concavity, threshold) {
21+
.Call('_ggforce_concaveman_c', PACKAGE = 'ggforce', p, h, concavity, threshold)
22+
}
23+
2024
enclose_ellip_points <- function(x, y, id, tol) {
2125
.Call('_ggforce_enclose_ellip_points', PACKAGE = 'ggforce', x, y, id, tol)
2226
}

R/concaveman.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
concaveman <- function(points, concavity, threshold) {
2+
if (nrow(points) < 4) return(points)
3+
hull <- as.integer(grDevices::chull(points)) - 1L
4+
concaveman_c(points, hull, concavity, threshold)
5+
}

R/mark_hull.R

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@
3838
#' @name geom_mark_hull
3939
#' @rdname geom_mark_hull
4040
#'
41-
#' @examplesIf requireNamespace("concaveman", quietly = TRUE)
42-
#' ## requires the concaveman packages
41+
#' @examples
4342
#' ggplot(iris, aes(Petal.Length, Petal.Width)) +
4443
#' geom_mark_hull(aes(fill = Species, filter = Species != 'versicolor')) +
4544
#' geom_point()
@@ -108,8 +107,6 @@ GeomMarkHull <- ggproto('GeomMarkHull', GeomMarkCircle,
108107
con.cap = unit(3, 'mm'), con.arrow = NULL) {
109108
if (nrow(data) == 0) return(zeroGrob())
110109

111-
check_installed('concaveman', 'to calculate concave hulls')
112-
113110
# As long as coord$transform() doesn't recognise x0/y0
114111
data$xmin <- data$x0
115112
data$ymin <- data$y0
@@ -193,7 +190,6 @@ geom_mark_hull <- function(mapping = NULL, data = NULL, stat = 'identity',
193190
con.border = 'one', con.cap = unit(3, 'mm'),
194191
con.arrow = NULL, ..., na.rm = FALSE,
195192
show.legend = NA, inherit.aes = TRUE) {
196-
check_installed('concaveman', 'to calculate concave hulls')
197193
layer(
198194
data = data,
199195
mapping = mapping,
@@ -304,13 +300,13 @@ makeContent.hull_enc <- function(x) {
304300
if (length(unique0((yy[-1] - yy[1]) / (xx[-1] - xx[1]))) == 1) {
305301
return(mat[c(which.min(mat[, 1]), which.max(mat[, 1])), ])
306302
}
307-
concaveman::concaveman(mat, x$concavity, 0)
303+
concaveman(mat, x$concavity, 0)
308304
}, xx = x_new, yy = y_new)
309305
# ensure that all polygons have the same set of column names
310306
polygons <- lapply(polygons, function(x) {
311307
colnames(x) <- c("x", "y")
312-
return(x)}
313-
)
308+
return(x)
309+
})
314310
mark$id <- rep(seq_along(polygons), vapply(polygons, nrow, numeric(1)))
315311
polygons <- vec_rbind(!!!polygons)
316312
mark$x <- unit(polygons[, 1], 'mm')

man/geom_mark_hull.Rd

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/RcppExports.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ BEGIN_RCPP
6969
return rcpp_result_gen;
7070
END_RCPP
7171
}
72+
// concaveman_c
73+
NumericMatrix concaveman_c(NumericMatrix p, IntegerVector h, double concavity, double threshold);
74+
RcppExport SEXP _ggforce_concaveman_c(SEXP pSEXP, SEXP hSEXP, SEXP concavitySEXP, SEXP thresholdSEXP) {
75+
BEGIN_RCPP
76+
Rcpp::RObject rcpp_result_gen;
77+
Rcpp::RNGScope rcpp_rngScope_gen;
78+
Rcpp::traits::input_parameter< NumericMatrix >::type p(pSEXP);
79+
Rcpp::traits::input_parameter< IntegerVector >::type h(hSEXP);
80+
Rcpp::traits::input_parameter< double >::type concavity(concavitySEXP);
81+
Rcpp::traits::input_parameter< double >::type threshold(thresholdSEXP);
82+
rcpp_result_gen = Rcpp::wrap(concaveman_c(p, h, concavity, threshold));
83+
return rcpp_result_gen;
84+
END_RCPP
85+
}
7286
// enclose_ellip_points
7387
DataFrame enclose_ellip_points(NumericVector x, NumericVector y, IntegerVector id, double tol);
7488
RcppExport SEXP _ggforce_enclose_ellip_points(SEXP xSEXP, SEXP ySEXP, SEXP idSEXP, SEXP tolSEXP) {
@@ -115,6 +129,7 @@ static const R_CallMethodDef CallEntries[] = {
115129
{"_ggforce_getSplines", (DL_FUNC) &_ggforce_getSplines, 5},
116130
{"_ggforce_bezierPath", (DL_FUNC) &_ggforce_bezierPath, 3},
117131
{"_ggforce_getBeziers", (DL_FUNC) &_ggforce_getBeziers, 4},
132+
{"_ggforce_concaveman_c", (DL_FUNC) &_ggforce_concaveman_c, 4},
118133
{"_ggforce_enclose_ellip_points", (DL_FUNC) &_ggforce_enclose_ellip_points, 4},
119134
{"_ggforce_enclose_points", (DL_FUNC) &_ggforce_enclose_points, 3},
120135
{"_ggforce_points_to_path", (DL_FUNC) &_ggforce_points_to_path, 3},

src/concaveman.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include <Rcpp.h>
2+
#include "concaveman.h"
3+
4+
using namespace Rcpp;
5+
6+
// [[Rcpp::export]]
7+
NumericMatrix concaveman_c(NumericMatrix p, IntegerVector h, double concavity, double threshold) {
8+
typedef std::array<double, 2> point_type;
9+
std::vector<point_type> points(p.size());
10+
for (auto i = 0; i < p.size(); ++i) {
11+
points[i] = {p(i, 0), p(i, 1)};
12+
}
13+
std::vector<int> hull(h.size());
14+
for (auto i = 0; i < h.size(); ++i) {
15+
hull[i] = h[i];
16+
}
17+
18+
auto chull = concaveman<double, 16>(points, hull, concavity, threshold);
19+
20+
NumericMatrix res(chull.size(), 2);
21+
22+
for (auto i = 0; i < chull.size(); ++i) {
23+
res(i, 0) = chull[i][0];
24+
res(i, 1) = chull[i][1];
25+
}
26+
27+
return res;
28+
}

0 commit comments

Comments
 (0)