/
vol.R
179 lines (149 loc) · 4.78 KB
/
vol.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#' Plot a tetrahedral colour space
#'
#' Produces a 3D colour volume in tetrahedral colour space when plotting a
#' non-interactive tetrahedral plot.
#'
#' @inheritParams voloverlap
#' @param tcsdata (required) a data frame, possibly a result from the
#' [colspace()] or [tcspace()] function, containing values for the 'x', 'y'
#' and 'z' coordinates as columns (labeled as such).
#' @param avalue if `type = "alpha"`, which alpha parameter value should be used
#' to compute the alphashape. `avalue = "auto"` (default) finds and use the
#' \eqn{\alpha^*}{alpha*} value as defined in Gruson (2020).
#' @param alpha transparency of volume (if `fill = TRUE`).
#' @param grid logical. if `TRUE` (default), draws the polygon outline defined by the points.
#' @param fill logical. if `TRUE` (default), fills the volume defined by the points.
#' @param new logical. Should a new plot be started or draw over an open plot?
#' (defaults to `FALSE`)
#' @param ... additional graphical options. See [polygon()] and [tetraplot()].
#'
#' @return [vol()] creates a 3D colour volume within a static tetrahedral plot.
#'
#' @author Rafael Maia \email{rm72@@zips.uakron.edu}
#' @author Hugo Gruson
#'
#' @export
#'
#' @examples
#'
#' # For plotting
#' data(sicalis)
#' vis.sicalis <- vismodel(sicalis, visual = "avg.uv")
#' tcs.sicalis <- colspace(vis.sicalis, space = "tcs")
#' plot(tcs.sicalis)
#'
#' # Convex hull
#' vol(tcs.sicalis, type = "convex")
#'
#' # Alpha-shape
#' if (require("alphashape3d")) {
#' vol(tcs.sicalis, type = "alpha", avalue = 1)
#' }
#' @importFrom geometry convhulln
#' @importFrom graphics par polygon
#' @importFrom grDevices trans3d adjustcolor
#'
#' @inherit voloverlap references
#'
vol <- function(tcsdata, type = c("convex", "alpha"), avalue = "auto",
alpha = 0.2, grid = TRUE, fill = TRUE, new = FALSE, ...) {
oldpar <- par(no.readonly = TRUE)
on.exit(par(oldpar))
type <- match.arg(type)
if (!is.null(attr(tcsdata, "clrsp")) && attr(tcsdata, "clrsp") != "tcs") {
stop("object is not in tetrahedral color space", call. = FALSE)
}
if (type == "convex") {
coords <- tcsdata[, c("x", "y", "z")]
vol <- t(convhulln(coords, options = "FA")$hull)
} else {
if (!requireNamespace("alphashape3d", quietly = TRUE)) {
stop(
"Please install the alphashape3d package to be able to use ",
'type = "alpha"',
call. = FALSE
)
}
if (avalue == "auto") {
avalue <- find_astar(as.matrix(tcsdata[, c("x", "y", "z")]))
}
ashape <- alphashape3d::ashape3d(as.matrix(tcsdata[, c("x", "y", "z")]),
alpha = avalue
)
tri <- ashape$triang
vol <- t(tri[tri[, ncol(tri)] %in% c(2, 3), c(1, 2, 3)])
coords <- ashape$x
}
arg <- list(...)
if (new) {
argempty <- c(list(border = FALSE), arg)
argempty$col <- NULL
if (is.null(argempty$zoom)) {
argempty$zoom <- 1
}
if (is.null(argempty$xlim)) {
argempty$xlim <- range(tcsdata[, "x"]) / argempty$zoom
}
if (is.null(argempty$ylim)) {
argempty$ylim <- range(tcsdata[, "y"]) / argempty$zoom
}
if (is.null(arg$zlim)) {
argempty$zlim <- range(tcsdata[, "z"]) / argempty$zoom
}
argempty$zoom <- NULL
if (is.null(argempty$theta)) {
argempty$theta <- 45
}
if (is.null(argempty$phi)) {
argempty$phi <- 10
}
if (is.null(argempty$r)) {
argempty$r <- 12
}
if (is.null(argempty$box)) {
argempty$box <- FALSE
}
if (is.null(argempty$margin)) {
margin <- c(0, 0, 0, 0)
} else {
margin <- argempty$margin
argempty$margin <- NULL
}
argempty$x <- argempty$xlim
argempty$y <- argempty$ylim
argempty$z <- matrix(c(argempty$zlim, argempty$zlim), nrow = 2)
par(mar = margin)
P <- do.call(perspbox, argempty)
# Save plot info
assign("last_plot.tetra", P, envir = .PlotTetraEnv)
}
last_tetraplot <- get("last_plot.tetra", envir = .PlotTetraEnv)
flatcoords <- data.frame(trans3d(coords[, "x"], coords[, "y"], coords[, "z"], last_tetraplot))
if (is.null(arg$col)) {
arg$col <- "darkgrey"
}
darkcolor <- arg$col
alphacolor <- adjustcolor(arg$col, alpha.f = alpha)
if (fill) {
arg$border <- NA
arg$col <- alphacolor
} else {
arg$col <- NA
}
if (grid) {
arg$border <- darkcolor
}
# CRAN won't accept triple : arguments and persp.default is not exported,
# so we need to pass arguments by hand
perspargs <- c(
"x", "y", "z", "xlim", "ylim", "zlim", "xlab", "ylab", "zlab",
"main", "sub", "theta", "phi", "r", "d", "scale", "expand",
"ltheta", "lphi", "shade", "box", "axes", "nticks", "ticktype", "...", ""
)
arg[perspargs] <- NULL
for (i in seq_len(ncol(vol))) {
arg$x <- flatcoords[vol[, i], "x"]
arg$y <- flatcoords[vol[, i], "y"]
do.call(polygon, arg)
}
}