rgl/ 0000755 0001762 0000144 00000000000 14146502162 011037 5 ustar ligges users rgl/NAMESPACE 0000644 0001762 0000144 00000015144 14146177624 012276 0 ustar ligges users export(.check3d,
abclines3d, addNormals, addToSubscene3d, arc3d,
arrow3d, as.mesh3d, as.rglscene, as.tmesh3d, as.triangles3d, asRow,
ageSetter, asEuclidean, asEuclidean2, asHomogeneous, asHomogeneous2,
aspect3d, axes3d, axis3d, box3d,
bbox3d, bg3d, bgplot3d,
Buffer,
checkDeldir,
clear3d, clearSubsceneList, clipplanes3d, clipplaneSlider,
clipMesh3d, clipObj3d, close3d, compare_proxy.mesh3d,
contourLines3d,
cube3d, cuboctahedron3d, cur3d,
currentSubscene3d, cylinder3d,
decorate3d, deform.mesh3d, delFromSubscene3d, divide.mesh3d, dodecahedron3d, dot3d, drape3d, ellipse3d,
expect_known_scene, extrude3d,
facing3d, figWidth, figHeight, filledContour3d,
gc3d, getBoundary3d,
getr3dDefaults, getWidgetId, GramSchmidt, grid3d,
highlevel, hook_rgl, hook_webgl,
icosahedron3d, identify3d, identityMatrix, ids3d,
in_pkgdown_example,
layout3d, legend3d, light3d, lines3d, lowlevel, makeDependency, material3d,
matrixSetter, mergeVertices, mesh3d, mfrow3d, movie3d, mtext3d,
newSubscene3d, next3d, normalize.mesh3d, observer3d, octahedron3d, oh3d, open3d,
par3d, par3dinterp, par3dinterpControl, par3dinterpSetter,
particles3d, pch3d, persp3d, planes3d,
play3d, plot3d, plotmath3d, points3d,
polygon3d, pop3d, projectDown, propertySetter, propertySlider,
qmesh3d, quads3d, readOBJ, readSTL, rgl.abclines, rgl.bbox, rgl.bg, rgl.bringtotop, rgl.clear,
rgl.getAxisCallback, rgl.getMouseCallbacks, rgl.getWheelCallback,
rgl.close, rgl.cur, rgl.ids, rgl.init, rgl.light, rgl.lines, rgl.linestrips,
rgl.clipplanes, rgl.material, rgl.open, rgl.pixels, rgl.planes, rgl.points, rgl.pop, rgl.postscript,
rgl.primitive, rgl.projection, rgl.quads, rgl.quit, rgl.Sweave, rgl.Sweave.off,
rgl.select, rgl.select3d, rgl.set, rgl.snapshot, rgl.spheres, rgl.sprites,
rgl.surface, rgl.texts, rgl.triangles, rgl.user2window,
rgl.attrib, rgl.attrib.count, rgl.attrib.info, rgl.dev.list, rgl.useNULL,
rgl.viewpoint, rgl.window2user, rglExtrafonts,
rglFonts, rglId, rglMouse, rglShared, rglToLattice, rglToBase,
r3dDefaults, rotate3d, rotationMatrix,
scale3d, scaleMatrix, scene3d, segments3d,
select3d, selectionFunction3d, selectpoints3d,
rgl.setAxisCallback, rgl.setMouseCallbacks, rgl.setWheelCallback,
set3d, setAxisCallbacks, setGraphicsDelay, setupKnitr,
setUserCallbacks, setUserShaders, shade3d, shadow3d,
shapelist3d, shinyGetPar3d, shinySetPar3d, shinyResetBrush,
show2d, snapshot3d,
spheres3d, spin3d, sprites3d, subdivision3d,
subsceneInfo, subsceneList, subsetSetter, subsetSlider, Sweave.snapshot,
surface3d, tagged3d, terrain3d,
tetrahedron3d, text3d, texts3d,
thigmophobe3d, title3d,
tkpar3dsave, tkspinControl, tkspin3d,
toggleButton, toggleWidget, triangulate,
tmesh3d, transform3d, translate3d, translationMatrix, triangles3d,
turn3d, useSubscene3d, vertexSetter, view3d, wire3d,
writeASY, writeOBJ, writePLY, writeSTL, writeWebGL)
S3method(dot3d, shapelist3d)
S3method(wire3d, shapelist3d)
S3method(shade3d, shapelist3d)
S3method(translate3d, shapelist3d)
S3method(rotate3d, shapelist3d)
S3method(scale3d, shapelist3d)
S3method(addNormals, shapelist3d)
S3method(dot3d, mesh3d)
S3method(translate3d, mesh3d)
S3method(rotate3d, mesh3d)
S3method(scale3d, mesh3d)
S3method(merge, mesh3d)
S3method(wire3d, mesh3d)
S3method(shade3d, mesh3d)
S3method(subdivision3d, mesh3d)
S3method(addNormals, mesh3d)
S3method(plot3d, mesh3d)
S3method(all.equal, mesh3d)
S3method(all.equal, rglscene)
S3method(as.mesh3d, deldir)
S3method(as.mesh3d, tri)
S3method(as.mesh3d, triSht)
S3method(as.mesh3d, ashape3d)
S3method(as.mesh3d, rglId)
S3method(as.mesh3d, rglobject)
S3method(as.mesh3d, default)
S3method(as.tmesh3d, mesh3d)
S3method(as.tmesh3d, default)
S3method(as.triangles3d, mesh3d)
S3method(as.triangles3d, rglId)
S3method(translate3d, default)
S3method(rotate3d, default)
S3method(scale3d, default)
S3method(ellipse3d, default)
S3method(ellipse3d, lm)
S3method(ellipse3d, glm)
S3method(ellipse3d, nls)
S3method(plot3d, default)
S3method(persp3d, default)
S3method(persp3d, "function")
S3method(persp3d, deldir)
S3method(persp3d, tri)
S3method(persp3d, triSht)
S3method(persp3d, ashape3d)
S3method(persp3d, formula)
S3method(plot3d, rglscene)
S3method(plot3d, rglobject)
S3method(plot3d, rglbboxdeco)
S3method(plot3d, rglbackground)
S3method(plot3d, rglsubscene)
S3method(plot3d, rglWebGL)
S3method(plot3d, "function")
S3method(plot3d, deldir)
S3method(plot3d, tri)
S3method(plot3d, triSht)
S3method(plot3d, ashape3d)
S3method(plot3d, formula)
S3method(plot3d, lm)
S3method(print, rglscene)
S3method(print, rglobject)
S3method(print, rglsubscene)
S3method(print, indexedSetter)
S3method(print, rglId)
S3method(print, rglOpen3d)
S3method(print, mesh3d)
S3method(print, shapelist3d)
S3method(print, rglMouseSelection)
S3method(knit_print, rglId)
S3method(knit_print, rglOpen3d)
S3method(summary, rglscene)
S3method(summary, rglsubscene)
S3method(drape3d, default)
S3method(drape3d, mesh3d)
S3method(contourLines3d, rglId)
S3method(contourLines3d, mesh3d)
S3method(filledContour3d, rglId)
S3method(filledContour3d, mesh3d)
S3method(sew, rglRecordedplot)
S3method(is_low_change, rglRecordedplot)
if(.Platform$OS.type == "windows") {
importFrom(utils, getWindowsHandle)
}
importFrom(graphics, legend, par, plot, plot.new, polygon,
strwidth, strheight)
importFrom(grDevices, col2rgb, colorRamp, dev.cur, dev.new,
dev.off, png, postscript, rgb, xy.coords, xyz.coords)
importFrom(stats, approxfun, get_all_vars, model.frame,
qchisq, qf, splinefun, terms, var)
importFrom(utils, capture.output, count.fields, file_test,
flush.console, packageVersion, read.table, head, tail)
importFrom(R6, R6Class)
# These were in rglwidget
export(rglwidget, renderRglwidget, rglwidgetOutput,
playwidget, renderPlaywidget, playwidgetOutput,
subsetControl, propertyControl, clipplaneControl, ageControl, vertexControl,
elementId2Prefix, registerSceneChange, sceneChange,
"%>%")
importFrom(htmlwidgets, createWidget, prependContent, saveWidget,
shinyRenderWidget, shinyWidgetOutput, sizingPolicy)
importFrom(htmltools, css, HTML, htmlDependency, img,
includeScript, tags, tagAppendAttributes,
tagHasAttribute, tagList, browsable, resolveDependencies)
importFrom(jsonlite, toJSON, base64_dec)
importFrom(knitr, asis_output, fig_path, hook_plot_custom, image_uri, include_graphics,
is_low_change, knit_hooks,
knit_meta_add, knit_print, opts_current, opts_hooks, opts_knit,
pandoc_to, sew)
importFrom(magrittr, "%>%")
importFrom(stats, coef, predict, residuals)
rgl/demo/ 0000755 0001762 0000144 00000000000 14137472630 011771 5 ustar ligges users rgl/demo/lollipop3d.R 0000644 0001762 0000144 00000011157 14100762640 014173 0 ustar ligges users
cone3d <- function(base,tip,rad,n=30,...) {
degvec <- seq(0,2*pi,length=n)
ax <- tip-base
## what do if ax[1]==0?
if (ax[1]!=0) {
p1 <- c(-ax[2]/ax[1],1,0)
p1 <- p1/sqrt(sum(p1^2))
if (p1[1]!=0) {
p2 <- c(-p1[2]/p1[1],1,0)
p2[3] <- -sum(p2*ax)
p2 <- p2/sqrt(sum(p2^2))
} else {
p2 <- c(0,0,1)
}
} else if (ax[2]!=0) {
p1 <- c(0,-ax[3]/ax[2],1)
p1 <- p1/sqrt(sum(p1^2))
if (p1[1]!=0) {
p2 <- c(0,-p1[3]/p1[2],1)
p2[3] <- -sum(p2*ax)
p2 <- p2/sqrt(sum(p2^2))
} else {
p2 <- c(1,0,0)
}
} else {
p1 <- c(0,1,0); p2 <- c(1,0,0)
}
ecoord2 <- function(theta) {
base+rad*(cos(theta)*p1+sin(theta)*p2)
}
for (i in seq_len(n-1)) {
li <- ecoord2(degvec[i])
lj <- ecoord2(degvec[i+1])
triangles3d(c(li[1],lj[1],tip[1]),c(li[2],lj[2],tip[2]),c(li[3],lj[3],tip[3]),...)
}
}
lollipop3d <- function(data.x,data.y,data.z,surf.fun,surf.n=50,
xlim=range(data.x),
ylim=range(data.y),
zlim=range(data.z),
asp=c(y=1,z=1),
xlab=deparse(substitute(x)),
ylab=deparse(substitute(y)),
zlab=deparse(substitute(z)),
alpha.surf=0.4,
col.surf=fg,col.stem=c(fg,fg),
col.pt="gray",type.surf="line",ptsize,
lwd.stem=2,lit=TRUE,bg="white",fg="black",
col.axes=fg,col.axlabs=fg,
axis.arrow=TRUE,axis.labels=TRUE,
box.col=bg,
axes=c("lines","box")) {
axes <- match.arg(axes)
col.stem <- rep(col.stem,length=2)
x.ticks <- pretty(xlim)
x.ticks <- x.ticks[x.ticks>=min(xlim) & x.ticks<=max(xlim)]
x.ticklabs <- if (axis.labels) as.character(x.ticks) else NULL
y.ticks <- pretty(ylim)
y.ticks <- y.ticks[y.ticks>=min(ylim) & y.ticks<=max(ylim)]
y.ticklabs <- if (axis.labels) as.character(y.ticks) else NULL
z.ticks <- pretty(zlim)
z.ticks <- z.ticks[z.ticks>=min(zlim) & z.ticks<=max(zlim)]
z.ticklabs <- if (axis.labels) as.character(z.ticks) else NULL
if (!missing(surf.fun)) {
surf.x <- seq(xlim[1],xlim[2],length=surf.n)
surf.y <- seq(ylim[1],ylim[2],length=surf.n)
surf.z <- outer(surf.x,surf.y,surf.fun) ## requires surf.fun be vectorized
z.interc <- surf.fun(data.x,data.y)
zdiff <- diff(range(c(surf.z,data.z)))
} else {
z.interc <- rep(min(data.z),length(data.x))
zdiff <- diff(range(data.z))
}
xdiff <- diff(xlim)
ydiff <- diff(ylim)
y.adj <- if (asp[1]<=0) 1 else asp[1]*xdiff/ydiff
data.y <- y.adj*data.y
y.ticks <- y.adj*y.ticks
ylim <- ylim*y.adj
ydiff <- diff(ylim)
z.adj <- if (asp[2]<=0) 1 else asp[2]*xdiff/zdiff
data.z <- z.adj*data.z
if (!missing(surf.fun)) {
surf.y <- y.adj*surf.y
surf.z <- z.adj*surf.z
}
z.interc <- z.adj*z.interc
z.ticks <- z.adj*z.ticks
zlim <- z.adj*zlim
open3d()
clear3d("all")
light3d()
bg3d(color=c(bg,fg))
if (!missing(surf.fun))
surface3d(surf.x,surf.y,surf.z,alpha=alpha.surf,
front=type.surf,back=type.surf,
col=col.surf,lit=lit)
if (missing(ptsize)) ptsize <- 0.02*xdiff
## draw points
spheres3d(data.x,data.y,data.z,r=ptsize,lit=lit,color=col.pt)
## draw lollipops
apply(cbind(data.x,data.y,data.z,z.interc),1,
function(X) {
lines3d(x=rep(X[1],2),
y=rep(X[2],2),
z=c(X[3],X[4]),
col=ifelse(X[3]>X[4],col.stem[1],
col.stem[2]),lwd=lwd.stem)
})
if (axes=="box") {
bbox3d(xat=x.ticks,xlab=x.ticklabs,
yat=y.ticks,ylab=y.ticklabs,
zat=z.ticks,zlab=z.ticklabs,lit=lit)
} else if (axes=="lines") { ## set up axis lines
axis3d(edge="x",at=x.ticks,labels=x.ticklabs,
col=col.axes,arrow=axis.arrow)
axis3d(edge="y",at=y.ticks,labels=y.ticklabs,
col=col.axes,arrow=axis.arrow)
axis3d(edge="z",at=z.ticks,labels=z.ticklabs,
col=col.axes,arrow=axis.arrow)
box3d(col=col.axes)
}
decorate3d(xlab=xlab, ylab=ylab, zlab=zlab, box=FALSE, axes=FALSE, col=col.axlabs)
}
x <- 1:5
y <- x*10
z <- (x+y)/20
open3d()
spheres3d(x,y,z)
axes3d()
set.seed(1001)
x <- runif(30)
y <- runif(30,max=2)
dfun <- function(x,y) 2*x+3*y+2*x*y+3*y^2
z <- dfun(x,y)+rnorm(30,sd=0.5)
## lollipops only
lollipop3d(x,y,z)
## lollipops plus theoretical surface
lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue"))
## lollipops plus regression fit
linmodel <- lm(z~x+y)
dfun <- function(x,y) predict(linmodel,newdata=data.frame(x=x,y=y))
lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue"))
####
rgl/demo/shinyMouse.R 0000644 0001762 0000144 00000006567 14137472630 014275 0 ustar ligges users # Use the mouse to select points
# Original version written by Yohann Demont
if (!require("shiny"))
stop("This demo requires shiny.")
if (!requireNamespace("crosstalk"))
stop("This demo requires crosstalk.")
library(rgl)
ui <- fluidPage(
sidebarLayout(
mainPanel(tabsetPanel(id = "navbar",
selected = "3D",
tabPanel(title = "2D",
plotOutput("plot_2D", brush = brushOpts(id = "plot_2D_brush",
resetOnNew = TRUE,
direction = "xy")),
verbatimTextOutput("brush_info_2D")),
tabPanel(title = "3D",
uiOutput("plot_3D_mousemode"),
rglwidgetOutput("plot_3D"),
verbatimTextOutput("brush_info_3D"),
verbatimTextOutput("selected"))
)),
sidebarPanel(selectInput("plot_x", label = "x feature", choices = colnames(iris)[-5], selected = colnames(iris)[1]),
selectInput("plot_y", label = "y feature", choices = colnames(iris)[-5], selected = colnames(iris)[2]),
selectInput("plot_z", label = "z feature", choices = colnames(iris)[-5], selected = colnames(iris)[3]),
actionButton(inputId = "reset_brush", label = "reset brush"))
))
server <- function(input, output, session) {
# 2D
output$plot_2D <- renderPlot({
plot(x = iris[, input$plot_x],
y = iris[, input$plot_y],
col = as.integer(iris[, "Species"]))
})
output$brush_info_2D <- renderPrint(str(input$plot_2D_brush))
# 3D
sharedData <- NULL
output$brush_info_3D <- renderPrint(print(input$rgl_3D_brush, verbose = TRUE))
# How to use selectionFunction3d ?
output$selected <- renderPrint({
if(length(input$rgl_3D_brush) == 0 || input$rgl_3D_brush$state == "inactive") return(NULL)
cat("Selections from crosstalk:\n")
# Need as.logical because selection() might return NULL
print(which(as.logical(sharedData$selection())))
cat("Selections using function:\n")
f <- selectionFunction3d(input$rgl_3D_brush)
which(f(iris[, c(input$plot_x, input$plot_y, input$plot_z)]))
})
output$plot_3D_mousemode <-
renderUI({
rglMouse( default = "trackball",
stayActive = FALSE,
choices = c("trackball", "selecting"),
sceneId = "plot_3D")
})
open3d(useNULL = TRUE)
output$plot_3D <- renderRglwidget({
clear3d()
dat <- iris[, c(input$plot_x, input$plot_y, input$plot_z, "Species")]
dat$id <-as.character(seq_len(nrow(iris)))
plot3d(x = dat[, 1:3], type = "s", size = 1, col = as.integer(iris[, "Species"]), aspect = TRUE)
sharedData <<- rglShared(id = text3d(dat[, 1:3], text = dat[, "id"], adj = -0.5),
group = "SharedData_plot_3D_ids",
deselectedFade = 0,
selectedIgnoreNone = FALSE)
shinyResetBrush(session, "rgl_3D_brush")
rglwidget(shared = sharedData,
shinyBrush = "rgl_3D_brush")
})
observeEvent(input$reset_brush, {
session$resetBrush("plot_2D_brush")
shinyResetBrush(session, "rgl_3D_brush")
})
}
shinyApp(ui, server)
rgl/demo/mouseCallbacks.R 0000644 0001762 0000144 00000021346 14100762640 015043 0 ustar ligges users xprod <- function(a, b)
c(a[2]*b[3] - a[3]*b[2],
a[3]*b[1] - a[1]*b[3],
a[1]*b[2] - a[2]*b[1])
vlen <- function(a) sqrt(sum(a^2))
angle <- function(a,b) {
dot <- sum(a*b)
acos(dot/vlen(a)/vlen(b))
}
clamp <- function(x, min, max) pmin(pmax(x, min), max)
mouseNone <- function(button = 1, dev = cur3d() ) {
cur <- cur3d()
for (i in dev) {
set3d(i, TRUE)
rgl.setMouseCallbacks(button, begin = NULL, update = NULL, end = NULL, dev = dev)
}
set3d(cur)
}
mouseTrackball <- function(button = 1, dev = cur3d() ) {
width <- height <- rotBase <- NULL
userMatrix <- list()
cur <- cur3d()
screenToVector <- function(x, y) {
radius <- max(width, height)/2
centre <- c(width, height)/2
pt <- (c(x, y) - centre)/radius
len <- vlen(pt)
if (len > 1.e-6) pt <- pt/len
maxlen <- sqrt(2)
angle <- (maxlen - len)/maxlen*pi/2
z <- sin(angle)
len <- sqrt(1 - z^2)
pt <- pt * len
return(c(pt, z))
}
trackballBegin <- function(x, y) {
vp <- par3d("viewport")
width <<- vp[3]
height <<- vp[4]
cur <<- cur3d()
for (i in dev) {
if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i]
else userMatrix[[i]] <<- par3d("userMatrix")
}
set3d(cur, TRUE)
rotBase <<- screenToVector(x, height - y)
}
trackballUpdate <- function(x,y) {
rotCurrent <- screenToVector(x, height - y)
angle <- angle(rotBase, rotCurrent)
axis <- xprod(rotBase, rotCurrent)
mouseMatrix <- rotationMatrix(angle, axis[1], axis[2], axis[3])
for (i in dev) {
if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i]
else par3d(userMatrix = mouseMatrix %*% userMatrix[[i]])
}
set3d(cur, TRUE)
}
for (i in dev) {
set3d(i, TRUE)
rgl.setMouseCallbacks(button, begin = trackballBegin, update = trackballUpdate, end = NULL,
dev = dev)
}
set3d(cur, TRUE)
}
mouseXAxis<- function(button = 1, dev = cur3d() , left=TRUE) {
mouseOneAxis(button, dev, axis=c(1,0,0), left=left)
}
mouseYAxis<- function(button = 1, dev = cur3d(), left = TRUE ) {
mouseOneAxis(button, dev, axis=c(0,1,0), left=left)
}
mouseZAxis<- function(button = 1, dev = cur3d(), left=TRUE) {
mouseOneAxis(button, dev, axis=c(0,0,1), left=left)
}
mouseOneAxis <- function(button = 1, dev = cur3d(), axis = c(1,0,0), left = TRUE ) {
width <- height <- rotBase <- NULL
userMatrix <- list()
cur <- cur3d()
screenToVector <- function(x, y) {
radius <- max(width, height)/2
centre <- c(width, height)/2
pt <- (c(x, y) - centre)/radius
len <- vlen(pt)
if (len > 1.e-6) pt <- pt/len
maxlen <- sqrt(2)
angle <- (maxlen - len)/maxlen*pi/2
z <- sin(angle)
len <- sqrt(1 - z^2)
pt <- pt * len
return(c(pt, z))
}
oneAxisBegin <- function(x, y) {
vp <- par3d("viewport")
width <<- vp[3]
height <<- vp[4]
cur <<- cur3d()
for (i in dev) {
if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i]
else userMatrix[[i]] <<- par3d("userMatrix")
}
set3d(cur, TRUE)
rotBase <<- screenToVector(x, height/2)
}
oneAxisUpdate <- function(x,y) {
rotCurrent <- screenToVector(x, height/2)
angle <- rotCurrent[1] - rotBase[1]
mouseMatrix <- rotationMatrix(angle, axis[1], axis[2], axis[3])
for (i in dev) {
if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i]
else {
if (left)
par3d(userMatrix = mouseMatrix %*% userMatrix[[i]])
else
par3d(userMatrix = userMatrix[[i]] %*% mouseMatrix)
}
}
set3d(cur, TRUE)
}
for (i in dev) {
set3d(i, TRUE)
rgl.setMouseCallbacks(button, begin = oneAxisBegin, update = oneAxisUpdate, end = NULL, dev = dev)
}
set3d(cur, TRUE)
}
mousePolar <- function(button = 1, dev = cur3d()) {
screenToPolar <- function(x,y) {
r <- min(width, height)/2
dx <- clamp(x - width/2, -r, r)
dy <- clamp(y - height/2, -r, r)
return( asin( c(dx, -dy)/r ) )
}
cur <- cur3d()
width <- height <- dragBase <- dragCurrent <- NULL
camBase <- list()
polarBegin <- function(x, y) {
vp <- par3d("viewport")
width <<- vp[3]
height <<- vp[4]
dragBase <<- screenToPolar(x, y)
cur <<- cur3d()
for (i in dev) {
if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i]
else {
m <- par3d("userMatrix")
svd <- svd(m[1:3, 1:3])
m[1:3, 1:3] <- svd$u %*% t(svd$v)
theta <- atan2(-m[1,3], m[1,1])
m <- m %*% rotationMatrix(theta, 0,1,0)
svd <- svd(m[1:3, 1:3])
m[1:3,1:3] <- svd$u %*% t(svd$v)
phi <- atan2(-m[2,3], m[3,3])
camBase[[i]] <<- c(theta, phi)
}
}
set3d(cur, TRUE)
}
polarUpdate <- function(x,y) {
dragCurrent <<- screenToPolar(x, y)
for (i in dev) {
if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i]
else {
newpos <- camBase[[i]] - ( dragCurrent - dragBase )
newpos[2] <- clamp(newpos[2], -pi/2, pi/2)
mouseMatrix <- rotationMatrix(newpos[2], 1, 0, 0) %*% rotationMatrix(-newpos[1], 0, 1, 0)
par3d(userMatrix = mouseMatrix)
}
}
set3d(cur, TRUE)
}
for (i in dev) {
set3d(i, TRUE)
rgl.setMouseCallbacks(button, begin = polarBegin, update = polarUpdate, end = NULL, dev = dev)
}
set3d(cur, TRUE)
}
# Set background colour based on x,y position in the window
mouseBG <- function(button = 1, dev = cur3d(), init = "white", rate = cbind(c(1,0,1),c(0,1,1)), space = c("rgb", "hsv")) {
cur <- cur3d()
space <- match.arg(space)
init <- col2rgb(init)/255
if (space == "hsv")
init <- rgb2hsv(init*255)
width <- height <- lambda0 <- lambda <- NULL
bgBegin <- function(x, y) {
lambda0 <<- c(x/width, 1-y/height) # nolint
vp <- par3d("viewport")
width <<- vp[3]
height <<- vp[4]
}
bgUpdate <- function(x,y) {
lambda <<- c(x/width, 1-y/height) - lambda0
color <- clamp(init + rate %*% lambda, 0, 1)
x <- color[1]
y <- color[2]
z <- color[3]
if (space == "rgb")
color <- rgb(x,y,z)
else
color <- hsv(x,y,z)
for (i in dev) {
if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i]
else bg3d(color=color)
}
set3d(cur, TRUE)
}
bgEnd <- function() {
init <<- clamp(init + rate %*% lambda, 0, 1)
}
for (i in dev) {
set3d(i, TRUE)
rgl.setMouseCallbacks(button, begin = bgBegin, update = bgUpdate, end = bgEnd, dev = dev)
}
set3d(cur, TRUE)
}
# Set time using an arbitrary par3dinterp function
mouseInterp <- function(button = 1, dev = cur3d(), fn, init = 0, range = NULL, direction=c(1,0)) {
cur <- cur3d()
time <- init
x0 <- width <- NULL
interpBegin <- function(x, y) {
vp <- par3d("viewport")
width <<- vp[3]
x0 <<- sum(direction*c(x,y))
}
interpUpdate <- function(x,y) {
time <<- init + (sum(direction*c(x,y)) - x0)/width
if (!is.null(range)) time <<- clamp(time, range[1], range[2])
for (i in dev) {
if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i]
else par3d(fn(time))
}
set3d(cur, TRUE)
}
interpEnd <- function() {
init <<- time
}
for (i in dev) {
set3d(i, TRUE)
rgl.setMouseCallbacks(button, begin = interpBegin, update = interpUpdate, end = interpEnd, dev = dev)
}
set3d(cur, TRUE)
}
mouseZoom <- function(button = 1, dev = cur3d())
mouseInterp(button,dev=dev,fn=par3dinterp(times=c(-4,4)/4, zoom=c(10^(-4),10^4),method="linear"),
init=log10(par3d("zoom"))/4,range=c(-4,4)/4,direction=c(0,-1))
mouseFOV <- function(button = 1, dev = cur3d())
mouseInterp(button,dev=dev,fn=par3dinterp(times=c(1,179)/180, FOV=c(1,179),method="linear"),
init=par3d("FOV")/180, range = c(1,179)/180, direction=c(0,1))
# Synchronize mouse control of two windows for stereo view
example(surface3d, echo = FALSE)
par3d(windowRect= c(0,32,512,544), userMatrix = rotationMatrix(5*pi/180, 0,1,0) %*% par3d("userMatrix") )
w1 <- cur3d()
example(surface3d, echo = FALSE)
par3d(windowRect = c(512,32,1024,544))
w2 <- cur3d()
mouseTrackball(dev=c(w1,w2))
mouseZoom(2,dev=c(w1,w2))
mouseFOV(3,dev=c(w1,w2))
rgl/demo/shinyToggle.R 0000644 0001762 0000144 00000001322 14100762640 014377 0 ustar ligges users if (!require("shiny"))
stop("This demo requires shiny.")
library(rgl)
open3d(useNULL = TRUE)
ids <- plot3d(rnorm(100), rnorm(100), rnorm(100))["data"]
scene <- scene3d()
close3d()
ui <- fluidPage(
checkboxInput("chk", label = "Display", value = FALSE),
playwidgetOutput("control"),
rglwidgetOutput("wdg")
)
server <- function(input, output, session) {
options(rgl.useNULL = TRUE)
save <- options(rgl.inShiny = TRUE)
on.exit(options(save))
output$wdg <- renderRglwidget({
rglwidget(scene, controllers = "control")
})
output$control <- renderPlaywidget({
toggleWidget("wdg", respondTo = "chk",
ids = ids)
})
}
if (interactive())
shinyApp(ui = ui, server = server)
rgl/demo/stereo.R 0000644 0001762 0000144 00000012465 14100762640 013416 0 ustar ligges users randomDot <- function(left, right, rightOffset=c(200, 0), n=3000, ...) {
old <- cur3d()
on.exit(set3d(old))
force(left)
force(right)
set3d(left)
leftViewport <- par3d("viewport")
leftSize <- leftViewport[3:4]
leftProj <- rgl.projection()
leftDepth <- rgl.pixels("depth")
leftUR <- leftViewport[1:2] + leftSize - 1
set3d(right)
rightViewport <- par3d("viewport")
rightSize <- rightViewport[3:4]
rightProj <- rgl.projection()
rightDepth <- rgl.pixels("depth")
rightUR <- rightViewport[1:2] + rightSize - 1
size <- pmax(leftViewport[3:4], rightViewport[3:4]+rightOffset)
pts <- matrix(c(sample(leftSize[1], n, replace=TRUE),
sample(leftSize[2], n, replace=TRUE)), n, 2)
cols <- 1:n
startpt <- pts
startcols <- cols
keep <- startpt[,1] < leftSize[1] & startpt[,2] < leftSize[2]
pt <- startpt[keep,,drop=FALSE]
cl <- startcols[keep]
while (length(pt)) {
depth <- leftDepth[pt]
user <- rgl.window2user((pt[,1]-0.5)/leftSize[1], (pt[,2]-0.5)/leftSize[2],
depth, projection=leftProj)
win <- rgl.user2window(user, projection=rightProj)
bkgd <- cbind((pt[,1] - 0.5)/rightSize[1], (pt[,2] - 0.5)/rightSize[2], 1)
usewin <- rep(depth < 1, 3)
rightPt <- structure(ifelse(usewin, win, bkgd), dim=dim(win))
rightPti <- round(cbind(rightSize[1]*rightPt[,1], rightSize[2]*rightPt[,2]) + 0.5)
keep <- rightPti[,1] >= 1 & rightPti[,1] <= rightUR[1] &
rightPti[,2] >= 1 & rightPti[,2] <= rightUR[2]
rightPti <- rightPti[keep,,drop=FALSE]
rightPt <- rightPt[keep,,drop=FALSE]
cl <- cl[keep]
keep <- TRUE | rightPt[,3] <= rightDepth[ rightPti ]+0.001
rightPti <- rightPti[keep,,drop=FALSE]
cl <- cl[keep]
pt <- cbind(rightPti[,1] + rightOffset[1], rightPti[,2] + rightOffset[2])
pts <- rbind(pts, pt)
cols <- c(cols, cl)
keep <- apply(pt, 1, min) >= 1 &
pt[,1] <= leftUR[1] &
pt[,2] <= leftUR[2]
pt <- pt[keep,,drop=FALSE]
cl <- cl[keep]
}
pt <- cbind(startpt[,1] - rightOffset[1], startpt[,2] - rightOffset[2])
keep <- pt[,1] > 1 & pt[,1] < rightSize[1] &
pt[,2] > 1 & pt[,2] < rightSize[2]
pt <- pt[ keep,,drop=FALSE ]
cl <- startcols[ keep ]
while (length(pt)) {
depth <- rightDepth[pt]
user <- rgl.window2user((pt[,1]-0.5)/rightSize[1], (pt[,2]-0.5)/rightSize[2],
depth, projection=rightProj)
win <- rgl.user2window(user, projection=leftProj)
bkgd <- cbind((pt[,1] - 0.5)/leftSize[1], (pt[,2] - 0.5)/leftSize[2], 1)
usewin <- rep(depth < 1, 3)
leftPt <- structure(ifelse(usewin, win, bkgd), dim=dim(win))
leftPti <- round(cbind(leftSize[1]*leftPt[,1], leftSize[2]*leftPt[,2]) + 0.5)
keep <- leftPti[,1] >= 1 & leftPti[,1] <= leftUR[1] &
leftPti[,2] >= 1 & leftPti[,2] <= leftUR[2]
leftPti <- leftPti[keep,,drop=FALSE]
leftPt <- leftPt[keep,,drop=FALSE]
cl <- cl[keep]
keep <- TRUE | leftPt[,3] <= leftDepth[ leftPti ]+0.001
leftPti <- leftPti[keep,,drop=FALSE]
cl <- cl[keep]
pt <- leftPti
pts <- rbind(pts, pt)
cols <- c(cols, cl)
pt <- cbind(pt[,1] - rightOffset[1], pt[,2] - rightOffset[2])
keep <- apply(pt, 1, min) >= 1 &
pt[,1] <= rightUR[1] &
pt[,2] <= rightUR[2]
pt <- pt[keep,,drop=FALSE]
cl <- cl[keep]
}
plot(pts, col = cols, pch=16, axes=FALSE,cex=0.25+cols/n/2,xlab="",ylab="",...)
rug((size[1] + c(-1,1)*rightOffset[1])/2, side=1)
rug((size[1] + c(-1,1)*rightOffset[1])/2, side=3)
rug((size[2] + c(-1,1)*rightOffset[2])/2, side=2)
rug((size[2] + c(-1,1)*rightOffset[2])/2, side=4)
}
#red #cyan
anaglyph <- function(left, right, leftColor = c(1,0,0), rightColor = c(0,1,1),
dimens = dim(leftPixels)) {
old <- cur3d()
on.exit(set3d(old))
force(left)
force(right)
set3d(left)
vp <- par3d("viewport")
leftPixels <- rgl.pixels(viewport=vp)
leftPixels <- t((leftPixels[,,1]+leftPixels[,,2]+leftPixels[,,3])/3)
leftPixels <- leftPixels[rev(seq_len(dimens[1])), seq_len(dimens[2])]
set3d(right)
rightPixels <- rgl.pixels(viewport=vp)
rightPixels <- t((rightPixels[,,1]+rightPixels[,,2]+rightPixels[,,3])/3)
rightPixels <- rightPixels[rev(seq_len(dimens[1])), seq_len(dimens[2])]
red <- pmin(leftPixels*leftColor[1] + rightPixels*rightColor[1], 1)
green <- pmin(leftPixels*leftColor[2] + rightPixels*rightColor[2], 1)
blue <- pmin(leftPixels*leftColor[3] + rightPixels*rightColor[3], 1)
z <- as.raster(array(c(red, green, blue), dim = c(dimens, 3)))
if (length(z)) {
par(mar = c(0,0,0,0))
plot(z)
} else {
cat("Unable to read pixels:\nstr(leftPixels):\n")
str(leftPixels)
cat("str(rightPixels):\n")
str(rightPixels)
}
}
if (!rgl.useNULL()) {
source(system.file("demo/mouseCallbacks.R", package="rgl"), echo=FALSE )
# This version assumes the eyes diverge for the stereo view.
# Reverse the two arguments for the cross-eyed view.
dev.new(width=9, height=7)
randomDot(cur3d()-1, cur3d())
# A red-cyan anaglyph (for 3D glasses). Use optional args to anaglyph for other glasses.
dev.new()
anaglyph(cur3d()-1, cur3d())
} else
cat("Can't read pixels from a NULL device\n")
rgl/demo/rgl.r 0000644 0001762 0000144 00000000202 14100762640 012723 0 ustar ligges users # all rgl demos
demo(hist3d)
demo(abundance)
demo(regression)
demo(lsystem)
demo(subdivision)
# requires MASS library
demo(bivar)
rgl/demo/flag.R 0000644 0001762 0000144 00000001371 14100762640 013020 0 ustar ligges users
wave <- function(time) {
x <- seq(0,2, len=100)
wavefn <- function(x) x * sin(-5*time + 1.5 * (x/2) * 2*pi)/10
deriv <- function(x) (wavefn(x + 0.01) - wavefn(x - 0.01))/0.02
arclen <- cumsum(sqrt(1 + deriv(x)^2))*(x[2]-x[1])
keep <- arclen < 2
x <- x[keep]
y <- matrix(wavefn(x), length(x),20)
z <- matrix(seq(0,1, len=20), length(x), 20, byrow=TRUE)
arclen <- arclen[keep]
par3d(skipRedraw = TRUE)
if (nrow(ids3d())) pop3d()
surface3d(x,y,z, texture_s=matrix(arclen/2, length(x), 20), texture_t=z, col="white")
c(list(skipRedraw = FALSE), spin(time))
}
open3d()
material3d(texture = system.file("textures","rgl2.png", package="rgl"))
spin <- spin3d(rpm=6,axis=c(0,0,1))
if (!rgl.useNULL())
play3d(wave, 10, startTime = 5)
rgl/demo/shinyDemo.R 0000644 0001762 0000144 00000011376 14100762640 014054 0 ustar ligges users if (!require("shiny"))
stop("This demo requires shiny.")
library(rgl)
library(misc3d)
options(rgl.useNULL = TRUE)
set.seed(123)
ui <- fluidPage(
registerSceneChange(),
titlePanel("Nelder-Mead"),
sidebarLayout(
sidebarPanel(
helpText("The Nelder-Mead algorithm evaluates the function",
"on the vertices of a simplex. At each step it",
"moves one vertex of the simplex to a better value."),
sliderInput("Slider", min=0, max=59, step=1, value=0, label="Steps",
animate=animationOptions(200, loop=TRUE)),
sliderInput("Slider2", min=0, max=59, step=1, value=0, label="Cumulative",
animate=animationOptions(200, loop=TRUE)),
playwidgetOutput('thecontroller'),
playwidgetOutput('thecontroller2'),
actionButton('newStart', 'Restart')),
mainPanel(
rglwidgetOutput('thewidget', width = "100%", height = 512))
)
)
u1 <- runif(1)
u2 <- runif(1)*(1-u1)
u3 <- 1 - u1 - u2
# Example modified from ?contour3d
#Example 2: Nested contours of mixture of three tri-variate normal densities
nmix3 <- function(x, y, z, m, s) {
u1 * dnorm(x, m, s) * dnorm(y, m, s) * dnorm(z, m, s) +
u2 * dnorm(x, -m, s) * dnorm(y, -m, s) * dnorm(z, -m, s) +
u3 * dnorm(x, m, s) * dnorm(y, -1.5 * m, s) * dnorm(z, m, s)
}
f <- function(x,y,z) nmix3(x,y,z,.5,.5)
g <- function(n = 40, k = 5, alo = 0.1, ahi = 0.5, cmap = heat.colors) {
th <- seq(0.05, 0.2, len = k)
col <- rev(cmap(length(th)))
al <- seq(alo, ahi, len = length(th))
x <- seq(-2, 2, len=n)
bg3d(col="white")
contour3d(f,th,x,x,x,color=col,alpha=al) # nolint
}
f3 <- function(x) -f(x[1], x[2], x[3])
g(20,3)
surface <- scene3d()
close3d()
neldermead <- function(x, f) {
n <- nrow(x)
p <- ncol(x)
if (n != p + 1) stop(paste('Need', p + 1, 'starting points'))
fx <- rep(NA, n)
for (i in 1:n) fx[i] <- f(x[i,])
o <- order(fx)
fx <- fx[o]
x <- x[o,]
xmid <- apply(x[1:p,], 2, mean)
z1 <- xmid - (x[n,] - xmid)
fz1 <- f(z1)
if (fz1 < fx[1]) {
z2 <- xmid - 2*(x[n,] - xmid)
fz2 <- f(z2)
if (fz2 < fz1) {
x[n,] <- z2
} else {
x[n,] <- z1
}
} else if (fz1 < fx[p]) {
x[n,] <- z1
} else {
if (fz1 < fx[n]) {
x[n,] <- z1
fx[n] <- fz1
}
z3 <- xmid + (x[n,] - xmid)/2
fz3 <- f(z3)
if (fz3 < fx[n]) {
x[n,] <- z3
} else {
for (i in 2:n) {
x[i,] <- x[1,] + (x[i,] - x[1,])/2
}
}
}
return(x)
}
showsimplex <- function(x, f, col="blue") {
n <- nrow(x)
z <- numeric(n)
for (i in 1:n) z[i] <- f(x[i,])
xyz <- cbind(x, z)
# This is tricky:
# 1. draw all lines, taking vertices two at a time:
c(segments3d(xyz[as.numeric(combn(n, 2)),], col="black", depth_test = "lequal"),
# 2. draw all faces, taking vertices three at a time:
triangles3d(xyz[as.numeric(combn(n, 3)),], col=col, alpha=0.3))
}
setStartPoint <- function() {
xyz <- matrix(rnorm(12, sd=0.1) + rep(rnorm(3,sd=2), each=4), 4, 3)
subsets <-list()
for (i in 1:60) {
xyz <- neldermead(xyz,f3)
subset <- showsimplex(xyz,f3)
subsets <-c(subsets,list(subset))
}
names(subsets) <- seq_along(subsets)
subsets
}
server <- function(input, output, session) {
plot3d(surface)
dev <- cur3d()
save <- options(rgl.inShiny = TRUE)
on.exit(options(save))
session$onSessionEnded(function() {
set3d(dev)
close3d()
})
path <- reactiveValues(subsets = setStartPoint())
observeEvent(input$newStart, {
set3d(dev)
deletes <- unique(unlist(path$subsets))
if (length(deletes))
delFromSubscene3d(deletes)
subsets <- setStartPoint()
adds <- unique(unlist(subsets))
session$sendCustomMessage("sceneChange",
sceneChange("thewidget", delete = deletes, add = adds,
skipRedraw = TRUE))
path$subsets <- subsets
updateSliderInput(session, "Slider", value=0)
updateSliderInput(session, "Slider2", value=0)
session$onFlushed(function()
session$sendCustomMessage("sceneChange",
sceneChange("thewidget", skipRedraw = FALSE)))
})
output$thewidget <- renderRglwidget({
rglwidget(controllers=c("thecontroller", "thecontroller2"))
})
output$thecontroller <-
renderPlaywidget({
if (length(path$subsets))
playwidget("thewidget", respondTo = "Slider",
subsetControl(1, path$subsets),
start = 1, stop = length(path$subsets))
})
output$thecontroller2 <-
renderPlaywidget({
if (length(path$subsets))
playwidget("thewidget", respondTo = "Slider2",
subsetControl(1, path$subsets, accumulate = TRUE))
})
}
if (interactive())
shinyApp(ui = ui, server = server)
rgl/demo/regression.r 0000644 0001762 0000144 00000002145 14100762640 014327 0 ustar ligges users # demo: regression
# author: Daniel Adler
rgl.demo.regression <- function(n=100,xa=3,za=8,xb=0.02,zb=0.01,xlim=c(0,100),zlim=c(0,100)) {
rgl.clear("all")
rgl.bg(sphere = TRUE, color = c("black", "green"), lit = FALSE, size=2, alpha=0.2, back = "lines")
rgl.light()
rgl.bbox()
x <- runif(n,min=xlim[1],max=xlim[2])
z <- runif(n,min=zlim[1],max=zlim[2])
ex <- rnorm(n,sd=3)
ez <- rnorm(n,sd=2)
esty <- (xa+xb*x) * (za+zb*z) + ex + ez
rgl.spheres(x,esty,z,color="gray",radius=1.5,specular="green",
texture=system.file("textures/bump_dust.png",package="rgl"),
texmipmap=TRUE, texminfilter="linear.mipmap.linear")
regx <- seq(xlim[1],xlim[2],len=100)
regz <- seq(zlim[1],zlim[2],len=100)
regy <- (xa+regx*xb) %*% t(za+regz*zb)
rgl.surface(regx,regz,regy,color="blue",alpha=0.5,shininess=128)
lx <- c(xlim[1],xlim[2],xlim[2],xlim[1])
lz <- c(zlim[1],zlim[1],zlim[2],zlim[2])
f <- function(x,z) (xa+x*xb) * t(za+z*zb)
ly <- f(lx,lz)
rgl.quads(lx,ly,lz,color="red",size=5,front="lines",back="lines",lit=FALSE)
}
rgl.open()
rgl.demo.regression()
rgl/demo/shapes3d.R 0000644 0001762 0000144 00000006546 14100762640 013632 0 ustar ligges users
cone3d <- function(base=c(0,0,0),tip=c(0,0,1),rad=1,n=30,draw.base=TRUE,qmesh=FALSE,
trans = par3d("userMatrix"), ...) {
ax <- tip-base
if (missing(trans) && !cur3d()) trans <- diag(4)
### is there a better way?
if (ax[1]!=0) {
p1 <- c(-ax[2]/ax[1],1,0)
p1 <- p1/sqrt(sum(p1^2))
if (p1[1]!=0) {
p2 <- c(-p1[2]/p1[1],1,0)
p2[3] <- -sum(p2*ax)
p2 <- p2/sqrt(sum(p2^2))
} else {
p2 <- c(0,0,1)
}
} else if (ax[2]!=0) {
p1 <- c(0,-ax[3]/ax[2],1)
p1 <- p1/sqrt(sum(p1^2))
if (p1[1]!=0) {
p2 <- c(0,-p1[3]/p1[2],1)
p2[3] <- -sum(p2*ax)
p2 <- p2/sqrt(sum(p2^2))
} else {
p2 <- c(1,0,0)
}
} else {
p1 <- c(0,1,0); p2 <- c(1,0,0)
}
degvec <- seq(0,2*pi,length=n+1)[-1]
ecoord2 <- function(theta) {
base+rad*(cos(theta)*p1+sin(theta)*p2)
}
i <- rbind(1:n,c(2:n,1),rep(n+1,n))
v <- cbind(sapply(degvec,ecoord2),tip)
if (qmesh)
## minor kluge for quads -- draw tip twice
i <- rbind(i,rep(n+1,n))
if (draw.base) {
v <- cbind(v,base)
i.x <- rbind(c(2:n,1),1:n,rep(n+2,n))
if (qmesh) ## add base twice
i.x <- rbind(i.x,rep(n+2,n))
i <- cbind(i,i.x)
}
if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous
if (!qmesh)
triangles3d(v[1,i],v[2,i],v[3,i],...)
else
return(rotate3d(qmesh3d(v,i,material=list(...)), matrix=trans))
}
ellipsoid3d <- function(rx=1,ry=1,rz=1,n=30,ctr=c(0,0,0),
qmesh=FALSE,
trans = par3d("userMatrix"),...) {
if (missing(trans) && !cur3d()) trans <- diag(4)
degvec <- seq(0,pi,length=n)
ecoord2 <- function(p)
c(rx*cos(p[1])*sin(p[2]),ry*sin(p[1])*sin(p[2]),rz*cos(p[2]))
v <- apply(expand.grid(2*degvec,degvec),1,ecoord2)
if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous
e <- expand.grid(1:(n-1),1:n)
i1 <- apply(e,1,function(z)z[1]+n*(z[2]-1))
i2 <- i1+1
i3 <- (i1+n-1) %% n^2 + 1
i4 <- (i2+n-1) %% n^2 + 1
i <- rbind(i1,i2,i4,i3)
if (!qmesh)
quads3d(v[1,i],v[2,i],v[3,i],...)
else return(rotate3d(qmesh3d(v,i,material=list(...)),matrix=trans))
}
############
open3d()
ellipsoid3d(ctr=c(2,2,2),rx=3,ry=2,col="red",alpha=0.4)
cone3d(base=c(-2,-2,-2),rad=0.5,tip=c(-3,0,-4),col="blue",front="lines",back="lines")
shade3d(translate3d(cube3d(),3,-2,3,col="purple"))
### now with qmesh()
open3d()
q1 <- cone3d(qmesh=TRUE,trans=diag(4)) ## the "unit cone";
## height=1,radius=1, base at (0,0,0)
shade3d(q1)
## various transformations and rotations
wire3d(translate3d(q1,3,0,0),col="green")
wire3d(translate3d(scale3d(q1,1,1,2),6,0,0),col="green")
dot3d(translate3d(q1,0,3,0),col="green")
dot3d(translate3d(scale3d(q1,2,1,1),0,6,0),col="green")
shade3d(translate3d(q1,0,0,3),col="red")
shade3d(translate3d(rotate3d(scale3d(q1,1,1,2),pi/4,0,1,0),0,0,6),col="red")
axes3d()
open3d()
s1 <- ellipsoid3d(qmesh=TRUE,trans=diag(4)) ## the "unit sphere";
## radius=1, ctr at (0,0,0)
shade3d(s1)
## various transformations and rotations
wire3d(translate3d(s1,3,0,0),col="green")
wire3d(translate3d(scale3d(s1,1,1,2),6,0,0),col="green")
dot3d(translate3d(s1,0,3,0),col="green")
dot3d(translate3d(scale3d(s1,2,1,1),0,6,0),col="green")
shade3d(translate3d(s1,0,0,3),col="red")
shade3d(translate3d(rotate3d(scale3d(s1,1,1,2),pi/4,0,1,0),0,0,6),col="red")
axes3d()
rgl/demo/bivar.r 0000644 0001762 0000144 00000002021 14100762640 013243 0 ustar ligges users # rgl demo: rgl-bivar.r
# author: Daniel Adler
rgl.demo.bivar <- function() {
if (!requireNamespace("MASS", quietly = TRUE))
stop("This demo requires MASS")
# parameters:
n<-50; ngrid<-40
# generate samples:
set.seed(31415)
x<-rnorm(n); y<-rnorm(n)
# estimate non-parameteric density surface via kernel smoothing
denobj <- MASS::kde2d(x, y, n=ngrid)
den.z <-denobj$z
# generate parametric density surface of a bivariate normal distribution
xgrid <- denobj$x
ygrid <- denobj$y
bi.z <- dnorm(xgrid)%*%t(dnorm(ygrid))
# visualize:
zscale<-20
# New window
open3d()
# clear scene:
clear3d("all")
# setup env:
bg3d(color="#887777")
light3d()
# Draws the simulated data as spheres on the baseline
spheres3d(x,y,rep(0,n),radius=0.1,color="#CCCCFF")
# Draws non-parametric density
surface3d(xgrid,ygrid,den.z*zscale,color="#FF2222",alpha=0.5)
# Draws parametric density
surface3d(xgrid,ygrid,bi.z*zscale,color="#CCCCFF",front="lines")
}
rgl.demo.bivar()
rgl/demo/rglExamples.R 0000644 0001762 0000144 00000010550 14100762640 014371 0 ustar ligges users dirname <- tempfile()
dir.create(dirname)
olddir <- setwd(dirname)
show <- c() # list topics to show only those
skip <- c("rgl-package", "shinyGetPar3d", "tkpar3dsave", "tkrgl",
"tkspin3d", "tkspinControl") # Ones to skip
library(tools)
db <- Rd_db("rgl")
names <- names(db)
if (length(show))
names <- names[sub("[.]Rd$", "", names) %in% show]
Rmdnames <- sub("[.]Rd$", ".Rmd", names)
htmlnames <- sub("[.]Rd$", ".html", names)
# These functions are based on similar ones from tools
.Rd_deparse <- function (x, tag = TRUE)
{
if (!tag)
attr(x, "Rd_tag") <- "Rd"
paste(as.character(x), collapse = "")
}
.Rd_drop_nodes_with_tags <- function (x, tags)
{
recurse <- function(e) {
if (is.list(e))
structure(lapply(e[is.na(match(RdTags(e), tags))],
recurse), Rd_tag = attr(e, "Rd_tag"))
else e
}
recurse(x)
}
.Rd_drop_comments <- function (x)
.Rd_drop_nodes_with_tags(x, "COMMENT")
RdTags <- function (Rd)
{
res <- sapply(Rd, attr, "Rd_tag")
if (!length(res))
res <- character()
res
}
.Rd_get_section <- function (x, which, predefined = TRUE)
{
if (predefined)
x <- x[RdTags(x) == paste0("\\", which)]
else {
x <- x[RdTags(x) == "\\section"]
if (length(x)) {
ind <- sapply(x, function(e) .Rd_get_text(e[[1L]])) ==
which
x <- lapply(x[ind], `[[`, 2L)
}
}
if (!length(x))
x
else structure(x[[1L]], class = "Rd")
}
.Rd_get_example_code <- function (x)
{
x <- .Rd_get_section(x, "examples")
if (!length(x))
return(character())
x <- .Rd_drop_comments(x)
recurse <- function(e) {
if (is.list(e)) {
unlist(lapply(e[is.na(match(RdTags(e), c(#"\\donttest",
"\\dontrun")))],
recurse))
}
else e
}
.Rd_deparse(recurse(x), tag = FALSE)
}
writeIndex <- function(names, htmlnames, cols = 4) {
result <- character()
if (!is.null(text)) {
o <- order(names)
names <- names[o]
htmlnames <- htmlnames[o]
entries <- paste0("[", names, "](", htmlnames, ")")
len <- length(entries)
padding <- ((len + cols - 1) %/% cols) * cols - len
if (padding)
entries <- c(entries, rep("", length.out=padding))
result <- c(result, '\n
\n')
result <- c(result, knitr::kable(matrix(entries, ncol=cols), format="markdown",
col.names = rep(" ", cols)))
result <- c(result, "
\n")
}
}
library(rgl)
saveopts <- options(rgl.useNULL = TRUE)
prevlink <- "[Prev](index.html)"
indexlink <- "[Index](index.html)"
for (i in seq_along(names)) {
Rmd <- file(Rmdnames[i], open = "wt")
nextlink <- if (i < length(htmlnames)) paste0("[Next](", htmlnames[i+1], ")") else ""
writeLines(c('---', paste0('title: ', names[i]),
'output: html_document
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
initialWd <- getwd()
saveopts <- options()
options(rgl.useNULL = TRUE)
library(rgl)
setupKnitr(autoprint = TRUE)
example <- function(...) {
saveopts <- options(rgl.printRglwidget = FALSE)
on.exit(options(saveopts))
utils::example(...)
lowlevel(numeric())
}
options(ask = FALSE, examples.ask = FALSE, device.ask.default = FALSE)
```
'), Rmd)
writeLines(paste(prevlink, nextlink, indexlink), Rmd)
if (file_path_sans_ext(Rmdnames[i]) %in% skip)
writeLines(
'```{r eval = FALSE}
# This example is skipped in the demo.', Rmd)
else
writeLines('```{r}', Rmd)
code <- .Rd_get_example_code(db[[names[i]]])
if (length(code))
writeLines(code, Rmd)
else
writeLines("# No example code", Rmd)
writeLines(
'```
```{r echo=FALSE,include=FALSE}
setwd(initialWd)
while(length(rgl.dev.list())) close3d()
rm(examples)
options(saveopts)
```
', Rmd)
writeLines(paste(prevlink, nextlink, indexlink), Rmd)
close(Rmd)
prevlink <- paste0("[Prev](", htmlnames[i], ")")
rmarkdown::render(Rmdnames[i])
while(length(rgl.dev.list())) close3d()
}
indexname <- "index.Rmd"
index <- file(indexname, open = "wt")
writeLines(c(
'---
title: "rgl Examples"
author: "Duncan Murdoch"
output: html_document
---
These files show examples from almost every help file
in `rgl`.
',
writeIndex(names, htmlnames)), index)
close(index)
browseURL(rmarkdown::render(indexname))
options(saveopts)
setwd(olddir)
rgl/demo/lsystem.r 0000644 0001762 0000144 00000011167 14100762640 013653 0 ustar ligges users # demo: lsystem.r
# author: Daniel Adler
#
# geometry
#
deg2rad <- function( degree ) {
return( degree*pi/180 )
}
rotZ.m3x3 <- function( degree ) {
kc <- cos(deg2rad(degree))
ks <- sin(deg2rad(degree))
return(
matrix(
c(
kc, -ks, 0,
ks, kc, 0,
0, 0, 1
),ncol=3,byrow=TRUE
)
)
}
rotX.m3x3 <- function( degree ) {
kc <- cos(deg2rad(degree))
ks <- sin(deg2rad(degree))
return(
matrix(
c(
1, 0, 0,
0, kc, -ks,
0, ks, kc
),ncol=3,byrow=TRUE
)
)
}
rotY.m3x3 <- function( degree ) {
kc <- cos(deg2rad(degree))
ks <- sin(deg2rad(degree))
return(
matrix(
c(
kc, 0, ks,
0, 1, 0,
-ks, 0, kc
),ncol=3,byrow=TRUE
)
)
}
rotZ <- function( v, degree ) {
return( rotZ.m3x3(degree) %*% v)
}
rotX <- function( v, degree ) {
return( rotX.m3x3(degree) %*% v)
}
rotY <- function( v, degree ) {
return( rotY.m3x3(degree) %*% v)
}
#
# turtle graphics, rgl implementation:
#
turtle.init <- function(pos=c(0,0,0),head=0,pitch=90,roll=0,level=0) {
rgl.clear("all")
rgl.bg(color="black")
rgl.light()
return( list(pos=pos,head=head,pitch=pitch,roll=roll,level=level) )
}
turtle.move <- function(turtle, steps, color) {
rm <- rotX.m3x3(turtle$pitch) %*% rotY.m3x3(turtle$head) %*% rotZ.m3x3(turtle$roll)
from <- as.vector( turtle$pos )
dir <- rm %*% c(0,0,-1)
to <- from + dir * steps
x <- c( from[1], to[1] )
y <- c( from[2], to[2] )
z <- c( from[3], to[3] )
rgl.lines(x,y,z,col=color,size=1.5,alpha=0.5)
turtle$pos <- to
return(turtle)
}
turtle.pitch <- function(turtle, degree) {
turtle$pitch <- turtle$pitch + degree
return(turtle)
}
turtle.head <- function(turtle, degree) {
turtle$head <- turtle$head + degree
return(turtle)
}
turtle.roll <- function(turtle, degree) {
turtle$roll <- turtle$roll + degree
return(turtle)
}
#
# l-system general
#
lsystem.code <- function( x )
substitute( x )
lsystem.gen <- function( x, grammar, levels=0 ) {
code <- eval( substitute( substitute( REPLACE , grammar ), list(REPLACE=x) ) )
if (levels)
return( lsystem.gen( code , grammar , levels-1 ) )
else
return( code )
}
#
# l-system plot
#
lsystem.plot <- function( expr, level ) {
turtle <- turtle.init(level=level)
lsystem.eval( expr, turtle )
}
lsystem.eval <- function( expr, turtle ) {
if ( length(expr) == 3 ) {
turtle <- lsystem.eval( expr[[2]], turtle )
turtle <- lsystem.eval( expr[[3]], turtle )
turtle <- lsystem.eval( expr[[1]], turtle )
} else if ( length(expr) == 2 ) {
saved <- turtle
turtle <- lsystem.eval( expr[[1]], turtle )
turtle <- lsystem.eval( expr[[2]], turtle )
turtle <- saved
} else if ( length(expr) == 1 ) {
if ( as.name(expr) == "stem" ) turtle <- turtle.move(turtle, 5, "brown")
else if ( as.name(expr) == "short") turtle <- turtle.move(turtle, 5, "brown")
else if ( as.name(expr) == "leaf" ) {
rgl.spheres(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.1+turtle$level*0.3,color="green")
rgl.sprites(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.5+turtle$level*0.3 ,color="green",texture=system.file("textures/particle.png",package="rgl"),textype="alpha",alpha=0.5)
}
else if ( as.name(expr) == "roll" ) turtle <- turtle.head(turtle, 60)
else if ( as.name(expr) == "down" ) turtle <- turtle.pitch(turtle,10)
else if ( as.name(expr) == "up" ) turtle <- turtle.pitch(turtle,-10)
else if ( as.name(expr) == "left" ) turtle <- turtle.head(turtle, 1)
else if ( as.name(expr) == "right") turtle <- turtle.head(turtle,-1.5)
else if ( as.name(expr) == "turnleft") turtle <- turtle.head(turtle,20)
else if ( as.name(expr) == "turnright") turtle <- turtle.head(turtle,-20)
else if ( as.name(expr) == "turn") turtle <- turtle.roll(turtle,180)
}
return(turtle)
}
#
# example
#
simple <- function(level=0) {
grammar <- list(
stem=lsystem.code(
stem-(up-stem-leaf)-stem-(down-stem-leaf)-stem-leaf
)
)
plant <- lsystem.gen(lsystem.code(stem), grammar, level )
lsystem.plot(plant,level)
}
rgl.demo.lsystem <- function(level=0) {
gen <- list(
stem=lsystem.code(
stem-left-stem-branch( turnleft-down-short-turnleft-down-stem-leaf)-right-right-stem--branch( turnright-up-short-turnright-up-short-turnright-short-stem-leaf)-left-left-left-stem-branch( turnleft-down-short-turnright-down-stem-leaf )-branch( up-turnright-short-up-turnleft-up-stem-leaf )
)
)
plant <- lsystem.gen(lsystem.code(stem), gen, level )
lsystem.plot(plant,level)
}
rgl.open()
rgl.demo.lsystem(level=1)
rgl/demo/envmap.r 0000644 0001762 0000144 00000000733 14100762640 013436 0 ustar ligges users # RGL-Demo: environment mapping
# Author: Daniel Adler
rgl.demo.envmap <- function() {
open3d()
# Clear scene:
clear3d("all")
light3d()
bg3d(sphere=TRUE, color="white", back="filled"
, texture=system.file("textures/refmap.png",package="rgl")
)
data(volcano)
surface3d( 10*seq_len(nrow(volcano)),10*seq_len(ncol(volcano)),5*volcano
, texture=system.file("textures/refmap.png",package="rgl")
, texenvmap=TRUE
, color = "white"
)
}
rgl.demo.envmap()
rgl/demo/hist3d.r 0000644 0001762 0000144 00000006666 14100762640 013361 0 ustar ligges users
##########
### 3D HIST EXAMPLE:
##########
################################################################################
##### Required functions 'binplot' and 'hist3d':
binplot.3d<-function(x,y,z,alpha=1,topcol="#ff0000",sidecol="#aaaaaa") {
save <- par3d(skipRedraw=TRUE)
on.exit(par3d(save))
x1<-c(rep(c(x[1],x[2],x[2],x[1]),3),rep(x[1],4),rep(x[2],4))
z1<-c(rep(0,4),rep(c(0,0,z,z),4))
y1<-c(y[1],y[1],y[2],y[2],rep(y[1],4),rep(y[2],4),rep(c(y[1],y[2],y[2],y[1]),2))
x2<-c(rep(c(x[1],x[1],x[2],x[2]),2),rep(c(x[1],x[2],rep(x[1],3),rep(x[2],3)),2))
z2<-c(rep(c(0,z),4),rep(0,8),rep(z,8) )
y2<-c(rep(y[1],4),rep(y[2],4),rep(c(rep(y[1],3),rep(y[2],3),y[1],y[2]),2) )
rgl.quads(x1,z1,y1,col=rep(sidecol,each=4),alpha=alpha)
rgl.quads(c(x[1],x[2],x[2],x[1]),rep(z,4),c(y[1],y[1],y[2],y[2]),
col=rep(topcol,each=4),alpha=1)
rgl.lines(x2,z2,y2,col="#000000")
}
hist3d<-function(x,y=NULL,nclass="auto",alpha=1,col="#ff0000",scale=10) {
save <- par3d(skipRedraw=TRUE)
on.exit(par3d(save))
xy <- xy.coords(x,y)
x <- xy$x
y <- xy$y
n<-length(x)
if (nclass == "auto") nclass<-ceiling(sqrt(nclass.Sturges(x)))
breaks.x <- seq(min(x),max(x),length=(nclass+1))
breaks.y <- seq(min(y),max(y),length=(nclass+1))
z<-matrix(0,(nclass),(nclass))
for (i in seq_len(nclass)) {
for (j in seq_len(nclass)) {
z[i, j] <- (1/n)*sum(x < breaks.x[i+1] & y < breaks.y[j+1] &
x >= breaks.x[i] & y >= breaks.y[j])
binplot.3d(c(breaks.x[i],breaks.x[i+1]),c(breaks.y[j],breaks.y[j+1]),
scale*z[i,j],alpha=alpha,topcol=col)
}
}
}
################################################################################
rgl.open()
rgl.bg(color="gray")
rgl.light()
# Drawing a 'bin' for given coordinates:
binplot.3d(c(-0.5,0.5),c(4.5,5.5),2,alpha=0.6)
# Setting the viewpoint ('theta' and 'phi' have the same meaning as in persp):
rgl.viewpoint(theta=40,phi=40)
# Choosing a lightgrey background:
rgl.bg(col="#cccccc")
##### QUADS FORMING BIN:
rgl.open()
# Defining transparency and colors:
alpha<-0.7; topcol<-"#ff0000"; sidecol<-"#aaaaaa"
# Setting up coordinates for the quads and adding them to the scene:
y<-x<-c(-1,1) ; z<-4; of<-0.3
x12<-c(x[1],x[2],x[2],x[1]); x11<-rep(x[1],4); x22<-rep(x[2],4)
z00<-rep(0,4); z0z<-c(0,0,z,z); zzz<-rep(z,4); y11<-rep(y[1],4)
y1122<-c(y[1],y[1],y[2],y[2]); y12<-c(y[1],y[2],y[2],y[1]); y22<-rep(y[2],4)
rgl.quads(c(x12,x12,x11-of,x12,x22+of,x12),
c(z00-of,rep(z0z,4),zzz+of),
c(y1122,y11-of,y12,y22+of,y12,y1122),
col=rep(c(rep(sidecol,5),topcol),each=4),alpha=c(rep(alpha,5),1))
# Setting up coordinates for the border-lines of the quads and drawing them:
yl1<-c(y[1],y[2],y[1],y[2]); yl2<-c(y[1]-of,y[1]-of)
xl<-c(rep(x[1],8),rep(x[1]-of,8),rep(c(x[1],x[2]),8),rep(x[2],8),rep(x[2]+of,8))
zl<-c(0,z,0,z,z+of,z+of,-of,-of,0,0,z,z,0,z,0,z,rep(0,4),rep(z,4),rep(-of,4),
rep(z+of,4),z+of,z+of,-of,-of,rep(c(0,z),4),0,0,z,z)
yl<-c(yl2,y[2]+of,y[2]+of,rep(c(y[1],y[2]),4),y[1],y[1],y[2],y[2],yl2,
rep(y[2]+of,4),yl2,y[2],y[2],rep(y[1],4),y[2],y[2],yl1,yl2,y[2]+of,
y[2]+of,y[1],y[1],y[2],y[2],yl1)
rgl.lines(xl,zl,yl,col="#000000")
##### COMPLETE HISTOGRAM:
rgl.open()
# Choosing a lightgrey background:
rgl.bg(col="#cccccc")
# Setting the rng to a fixed value:
set.seed(1000)
# Drawing a 3d histogramm of 2500 normaly distributed observations:
hist3d(rnorm(2500),rnorm(2500),alpha=0.4,nclass=7,scale=30)
rgl/demo/simpleShinyRgl.R 0000644 0001762 0000144 00000001063 14100762640 015056 0 ustar ligges users # A simple Shiny demo written by Dieter Menne
options(rgl.useNULL = TRUE)
if (!require(shiny))
stop("This demo requires shiny.")
library(rgl)
app <- shinyApp(
ui = bootstrapPage(
checkboxInput("rescale", "Rescale"),
rglwidgetOutput("rglPlot")
),
server = function(input, output) {
output$rglPlot <- renderRglwidget({
try(close3d(), silent = TRUE)
if (input$rescale) aspect3d(1,1,10) else aspect3d(1,1,1)
spheres3d(rnorm(100), rnorm(100), rnorm(100,sd = 0.1), col = "red",
radius = 0.1)
axes3d()
rglwidget()
})
})
runApp(app)
rgl/demo/00Index 0000644 0001762 0000144 00000002146 14100762640 013117 0 ustar ligges users rgl RGL Demonstration
rglExamples All examples displayed in HTML
hist3d 3D histogram using basic building blocks
bivar Bivariate densities: kernel smoothing using rgl.surface and alpha-channel (requires MASS package)
abundance Animal abundance, visualization of multi-dimension data using multiple techniques
lsystem Plant modelling using a turtle and L-system
subdivision Subdivision surfaces using generic meshes (preview of generic 3D interface)
regression Bivariate regression
envmap Environment mapping
shapes3d 3D shape primitives (cones, ellipsoids, cubes), some taken from qmesh3d
lollipop3d "Lollipop" plots (3D scatterplot with lines between points and a surface)
flag play3d() function that waves a flag
mouseCallbacks Standard mouse handlers implemented in R, for a stereo view
stereo Stereo views using a random dot stereogram & an anaglyph
simpleShinyRgl Shiny demo with checkbox
shinyToggle Shiny with togglewidget
shinyTabs Shiny with tabs
shinyDemo rglwidget in Shiny: Nelder-Mead demonstration
shinyMouse Mouse selection in Shiny
rgl/demo/shinyTabs.R 0000644 0001762 0000144 00000001440 14100762640 014050 0 ustar ligges users if (!require("shiny"))
stop("This demo requires shiny.")
library(rgl)
options(rgl.useNULL = TRUE)
ui <- fluidPage(
mainPanel(
tabsetPanel(
tabPanel("red",
rglwidgetOutput('thewidget1')),
tabPanel("green",
rglwidgetOutput('thewidget2'))
))
)
server <- function(input, output, session) {
x <- rnorm(100)
y <- 2*rnorm(100)
z <- 10*rnorm(100)
open3d()
plot3d(x, y, z, col = "red")
scene1 <- scene3d()
plot3d(z, y, x, col = "green")
scene2 <- scene3d()
close3d()
save <- options(rgl.inShiny = TRUE)
on.exit(options(save))
output$thewidget1 <- renderRglwidget(
rglwidget(scene1)
)
output$thewidget2 <- renderRglwidget(
rglwidget(scene2)
)
}
if (interactive())
shinyApp(ui = ui, server = server) rgl/demo/subdivision.r 0000644 0001762 0000144 00000001222 14100762640 014500 0 ustar ligges users # RGL-demo: subdivision surfaces
# author: Daniel Adler
rgl.demo.subdivision <- function() {
# setup environment
clear3d("all")
view3d()
bg3d(color="gray")
light3d()
# generate basic mesh
obj <- oh3d()
part <- function( level, tx, ... ) {
shade3d( translate3d( obj, tx, 0, 0 )
, color="gray30", front="lines",alpha=0.5,back="lines", override=TRUE
)
shade3d( translate3d( subdivision3d( obj, depth=level ), tx, 0, 0 )
, override=TRUE, ... )
}
part(0, -5.50, color="blue" )
part(1, -1.75, color="yellow" )
part(2, 1.75, color="red" )
part(3, 5.50, color="green" )
}
open3d()
rgl.demo.subdivision()
rgl/demo/abundance.r 0000644 0001762 0000144 00000002447 14100762640 014074 0 ustar ligges users # RGL-Demo: animal abundance
# Authors: Oleg Nenadic, Daniel Adler
rgl.demo.abundance <- function() {
open3d()
clear3d("all") # remove all shapes, lights, bounding-box, and restore viewpoint
# Setup environment:
bg3d(col="#cccccc") # setup background
light3d() # setup head-light
# Importing animal data (created with wisp)
terrain<-dget(system.file("demodata/region.dat",package="rgl"))
pop<-dget(system.file("demodata/population.dat",package="rgl"))
# Define colors for terrain
zlim <- range(terrain)
colorlut <- terrain.colors(82)
col1 <- colorlut[9*sqrt(3.6*(terrain-zlim[1])+2)]
# Set color to (water-)blue for regions with zero 'altitude'
col1[terrain==0]<-"#0000FF"
# Add terrain surface shape (i.e. population density):
surface3d(
1:100,seq(1,60,length=100),terrain,
col=col1,spec="#000000", ambient="#333333", back="lines"
)
# Define colors for simulated populations (males:blue, females:red):
col2<-pop[,4]
col2[col2==0]<-"#3333ff"
col2[col2==1]<-"#ff3333"
# Add simulated populations as sphere-set shape
spheres3d(
pop[,1],
pop[,2],
terrain[cbind( ceiling(pop[,1]),ceiling(pop[,2]*10/6) )]+0.5,
radius=0.2*pop[,3], col=col2, alpha=(1-(pop[,5])/10 )
)
}
rgl.demo.abundance()
rgl/tools/ 0000755 0001762 0000144 00000000000 14100762641 012177 5 ustar ligges users rgl/tools/winlibs.R 0000644 0001762 0000144 00000000607 14100762641 013774 0 ustar ligges users VERSION <- commandArgs(TRUE)
if(!file.exists(sprintf("../windows/freetype-%s/include/freetype2/ft2build.h", VERSION))){
if(getRversion() < "3.3.0") setInternet2()
download.file(sprintf("https://github.com/rwinlib/freetype/archive/v%s.zip", VERSION), "lib.zip", quiet = TRUE)
dir.create("../windows", showWarnings = FALSE)
unzip("lib.zip", exdir = "../windows")
unlink("lib.zip")
}
rgl/README.md 0000644 0001762 0000144 00000015427 14146473076 012342 0 ustar ligges users
# RGL - 3D visualization device system for R using OpenGL

## INTRODUCTION
The RGL package is a visualization device system for R, using OpenGL or
WebGL as the rendering backend. An OpenGL rgl device at its core is a
real-time 3D engine written in C++. It provides an interactive viewpoint
navigation facility (mouse + wheel support) and an R programming
interface. WebGL, on the other hand, is rendered in a web browser; rgl
produces the input file, and the browser shows the images.
## WEBSITE
A `pkgdown` website is here:
The unreleased development version website is here:
See [this
vignette](https://dmurdoch.github.io/rgl/dev/articles/pkgdown.html) for
details on producing your own `pkgdown` website that includes `rgl`
graphics.
The currently active development site is here:
## NOTE ABOUT DEVEL VERSIONS
`rgl` can make use of development versions of some packages: `webshot2`,
`chromote`, `pkgdown`. Though it doesn’t require any of these, they each
provide some nice features:
- `webshot2` and `chromote` support good quality PNG snapshots of
`rgl` scenes, even on servers that don’t have a graphics display.
- The devel version of `pkgdown` supports inclusion of `rgl` graphics
in example code in automatically built package websites. (It also
supports inclusion of `htmlwidgets` for other dynamic web packages
like `plotly`, `leaflet`, etc.)
Unfortunately, being development versions, these packages sometimes
introduce bugs that break `rgl` usage. Currently (November 8, 2021) the
main branches of all packages are fine. I recommend the following code
to install them:
``` r
remotes::install_github(c("rstudio/webshot2",
"rstudio/chromote",
"r-lib/pkgdown"))
```
## INSTALLATION
Most users will want to install the latest CRAN release. For Windows,
macOS and some Linux platforms, installation can be easy, as CRAN
distributes binary versions:
# Install latest release from CRAN
install.packages("rgl")
To install the latest development version from Github, you’ll need to do
a source install. Those aren’t easy! Try
# Install development version from Github
remotes::install_github("dmurdoch/rgl")
If that fails, read the instructions below.
## LICENSE
The software is released under the GNU Public License. See
[COPYING](./COPYING) for details.
## FEATURES
- portable R package using OpenGL (if available) on macOS, Win32 and
X11
- can produce 3D graphics in web pages using WebGL
- R programming interface
- interactive viewpoint navigation
- automatic data focus
- geometry primitives: points, lines, triangles, quads, texts, point
sprites
- high-level geometry: surface, spheres
- up to 8 light sources
- alpha-blending (transparency)
- side-dependent fill-mode rendering (dots, wired and filled)
- texture-mapping with mipmapping and environment mapping support
- environmental effects: fogging, background sphere
- bounding box with axis ticks marks
- undo operation: shapes and light-sources are managed on type stacks,
where the top-most objects can be popped, or any item specified by
an identifier can be removed
## PLATFORMS
macOS Windows 7/10 Unix-derivatives
## BUILD TOOLS
R recommended tools (gcc toolchain) On Windows, Rtools40 (or earlier
versions for pre-R-4.0.0)
## REQUIREMENTS
**For OpenGL display:**
Windowing System (unix/x11 or Windows)
OpenGL Library
OpenGL Utility Library (GLU)
**For WebGL display:**
A browser with WebGL enabled. See .
## Installing OpenGL support
**Debian:**
aptitude install libgl1-mesa-dev libglu1-mesa-dev
**Fedora:**
yum install mesa-libGL-devel mesa-libGLU-devel libpng-devel
**macOS:**
Install XQuartz.
`rgl` should work with XQuartz 2.7.11 or newer, but it will probably
need rebuilding if the XQuartz version changes. XQuartz normally needs
re-installation whenever the macOS version changes.
**Windows:**
Windows normally includes OpenGL support, but to get the appropriate
include files etc., you will need the appropriate version of
[Rtools](https://cran.r-project.org/bin/windows/Rtools/) matched to your
R version.
## Options
The **libpng** library version 1.2.9 or newer is needed for pixmap
import/export support.
The **freetype** library is needed for resizable anti-aliased fonts. On
Windows, it will be downloaded from during
the install.
## BUILDING/INSTALLING
Binary builds of `rgl` are available for some platforms on CRAN.
For source builds, install the prerequisites as described above,
download the tarball and at the command line run
R CMD INSTALL rgl_0.108.3.tar.gz
(with the appropriate version of the tarball). The build uses an
`autoconf` configure script; to see the options, expand the tarball and
run `./configure --help`.
Alternatively, in R run
install.packages("rgl")
to install from CRAN, or
remotes::install_github("dmurdoch/rgl")
to install the development version from Github.
Sometimes binary development versions are available for Windows and
macOS using
install.packages("rgl", repos = "https://dmurdoch.github.io/drat",
type = "binary")
but these are not always kept up to date.
## BUILDING WITHOUT OPENGL
As of version 0.104.1, it is possible to build the package without
OpenGL support on Unix-alikes (including macOS) with the configure
option –disable-opengl For example,
R CMD INSTALL --configure-args="--disable-opengl" rgl_0.108.3.tar.gz
On Windows, OpenGL support cannot currently be disabled.
## DOCUMENTATION and DEMOS:
library(rgl)
browseVignettes("rgl")
demo(rgl)
## CREDITS
Daniel Adler
Duncan Murdoch
Oleg Nenadic
Simon Urbanek
Ming Chen
Albrecht Gebhardt
Ben Bolker
Gabor Csardi
Adam Strzelecki
Alexander Senger
The R Core Team for some code from R.
Dirk Eddelbuettel
The authors of Shiny for their private RNG code.
The authors of `knitr` for their graphics inclusion code. Jeroen Ooms
for `Rtools40` and `FreeType` help.
Yohann Demont for Shiny code, suggestions, and testing.
Joshua Ulrich for a lot of help with the Github migration. Xavier
Fernandez i Marin for help debugging the build.
George Helffrich for draping code.
Ivan Krylov for window_group code in X11.
Michael Sumner for as.mesh3d.default enhancement.
Tomas Kalibera for `winutf8` help.
rgl/man/ 0000755 0001762 0000144 00000000000 14146473375 011627 5 ustar ligges users rgl/man/snapshot.Rd 0000644 0001762 0000144 00000006560 14100762641 013747 0 ustar ligges users \name{snapshot3d}
\alias{rgl.snapshot}
\alias{snapshot3d}
\title{Export screenshot}
\description{
Saves the screenshot to a file.
}
\usage{
rgl.snapshot( filename, fmt = "png", top = TRUE )
snapshot3d( filename = tempfile(fileext = ".png"),
fmt = "png", top = TRUE,
..., scene, width = NULL, height = NULL,
webshot = TRUE)
}
\arguments{
\item{filename}{path to file to save.}
\item{fmt}{image export format, currently supported: png. Ignored if \code{webshot = TRUE}. }
\item{top}{whether to call \code{\link{rgl.bringtotop}}.
Ignored if \code{webshot = TRUE}.}
\item{...}{arguments to pass to \code{webshot2::webshot} }
\item{scene}{an optional result of \code{\link{scene3d}}
or \code{\link{rglwidget}} to plot}
\item{width, height}{optional specifications of output
size in pixels}
\item{webshot}{Use the \pkg{webshot2} package to take the
snapshot}
}
\details{
\code{rgl.snapshot()} is a low-level function
that copies the current RGL window from the screen. Users
should use \code{snapshot3d()} instead; it is more flexible,
and (if \pkg{webshot2} is installed) can take images even if
no window is showing, and they can be larger than the physical
screen.
Animations can be created in a loop modifying the scene and saving
each screenshot to a file. Various graphics programs (e.g. ImageMagick)
can put these together into a single animation. (See \code{\link{movie3d}} or
the example below.)
}
\value{
These functions are mainly called for the side effects. The
filename of the saved file is returned invisibly.
}
\note{
When \code{rgl.useNULL()} is \code{TRUE}, only \code{webshot = TRUE}
will produce a snapshot. It requires the \pkg{webshot2}
package, which as of this writing is not available on CRAN; to
install it, use \code{remotes::install_github("rstudio/webshot2")}
\code{rgl.snapshot} works by taking an image from the displayed
window on-screen.
On some systems, the snapshot
will include content from other windows if they cover the active RGL
window. Setting \code{top = TRUE} (the default) will use
\code{\link{rgl.bringtotop}} before the snapshot
to avoid this.
There are likely limits to how large \code{width} and
\code{height} can be set based on the display hardware; if these
are exceeded the results are undefined. A typical result
is that the snapshot will still be made but at a smaller
size.
There are slight differences between the displays with
\code{webshot = TRUE} and \code{webshot = FALSE}, as the
former are rendered using WebGL while the latter are rendered
using OpenGL. Often the \code{webshot = TRUE} displays have better quality.
}
\seealso{\code{\link{movie3d}}, \code{\link{rgl.viewpoint}}}
\examples{
if (interactive() && !in_pkgdown_example()) {
saveopts <- options(rgl.useNULL = TRUE)
plot3d(matrix(rnorm(300), ncol = 3, dimnames = list(NULL, c("x", "y", "z"))),
col = "red")
options(saveopts)
browseURL(snapshot3d())
}
\dontrun{
#
# create animation
#
shade3d(oh3d(), color = "red")
rgl.bringtotop()
view3d(0, 20)
olddir <- setwd(tempdir())
for (i in 1:45) {
view3d(i, 20)
filename <- paste("pic", formatC(i, digits = 1, flag = "0"), ".png", sep = "")
snapshot3d(filename)
}
## Now run ImageMagick in tempdir(). Use 'convert' instead of 'magick'
## if you have an older version of ImageMagick:
## magick -delay 10 *.png -loop 0 pic.gif
setwd(olddir)
}
}
\keyword{dynamic}
rgl/man/import.Rd 0000644 0001762 0000144 00000000626 14100762640 013416 0 ustar ligges users \name{import}
\alias{\%>\%}
\alias{pipe}
\docType{import}
\title{Imported from magrittr}
\description{
This object is imported from \pkg{magrittr}. Follow the link to its documentation.
\describe{
\item{magrittr}{\code{\link[magrittr:pipe]{\%>\%}}}
}
Pipes can be used to string together
\code{\link{rglwidget}} calls and \code{\link{playwidget}}
calls. See \code{\link{ageControl}} for an example.
}
rgl/man/rgl.Sweave.Rd 0000644 0001762 0000144 00000006315 14100762641 014123 0 ustar ligges users \name{rgl.Sweave}
\alias{rgl.Sweave}
\alias{rgl.Sweave.off}
\alias{Sweave.snapshot}
\title{
Integrating RGL with Sweave
}
\description{
As of \R 2.13.0, it is possible to include RGL graphics into
a \link{Sweave} document. These functions support that
integration.
}
\usage{
Sweave.snapshot()
rgl.Sweave(name, width, height, options, ...)
rgl.Sweave.off()
}
\arguments{
\item{name, width, height, options, ...}{
These arguments are passed by \code{\link{Sweave}} to \code{rgl.Sweave}
when it opens the device.
}
}
\details{
The \code{rgl.Sweave} function is not normally called by the user. The user
specifies it as the graphics driver when opening the code chunk, e.g. by
using
\preformatted{<>=}
When the RGL device is closed at the end of the code chunk,
\code{rgl.Sweave.off()} will be called automatically. It
will save a snapshot
of the last image (by default in \file{.png} format) for inclusion in the
Sweave document and (by default) close the device.
Alternatively, the \code{Sweave.snapshot()} function
can be called to save the image before the end of the chunk. Only one
snapshot will be taken per chunk.
Several chunk options are used by the \code{rgl.Sweave} device:
\describe{
\item{stayopen}{(default \code{FALSE}). If \code{TRUE} then the RGL
device will \emph{not} be closed at the end of the chunk,
instead a call to \code{Sweave.snapshot()}
will be used if it has not been called explicitly. Subsequent chunks can add
to the scene.}
\item{outputtype}{(default \code{png}). The output may be specified
as \code{outputtype = pdf} or \code{outputtype = eps} instead, in which case
the \code{\link{rgl.postscript}} function will be used to write output in the
specified format. Note that \code{\link{rgl.postscript}} has limitations
and does not always render scenes correctly.}
\item{delay}{(default 0.1). After creating the display window, \code{\link{Sys.sleep}}
will be called to delay this many seconds, to allow the display system to
initialize. This is needed in X11 systems which open the display
asynchronously. If the default time is too short, \code{rgl.Sweave} may
falsely report that the window is too large to open.}
}
}
\note{
We recommend turning off all other graphics drivers in a chunk that uses
\code{grdevice = rgl.Sweave}. The RGL functions do not write to
a standard graphics device.
}
\note{
The \pkg{rgl} package relies on your graphics hardware to render OpenGL scenes,
and the default \file{.png} output copies a bitmap from the hardware device. All
such devices have limitations on the size of the bitmap, but they do not
always signal these limitations in a way that RGL will detect. If you find
that images are not being produced properly, try reducing the size using
the \code{resolution}, \code{width} or \code{height} chunk options.
}
\value{
These functions are called for their side effects.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{RweaveLatex}} for a description of alternate graphics drivers
in Sweave, and standard options that can be used in code chunks.
\code{\link{hook_rgl}}
and \code{\link{hook_webgl}} allow fixed or interactive RGL
scenes to be embedded in \pkg{knitr}
documents.
}
\keyword{ utilities }
rgl/man/rglwidget.Rd 0000644 0001762 0000144 00000016350 14100762641 014076 0 ustar ligges users \name{rglwidget}
\alias{rglwidget}
\alias{rgl.printRglwidget}
\title{
An htmlwidget to hold an RGL scene
}
\description{
The \pkg{htmlwidgets} package provides a framework for embedding
graphical displays in HTML documents of various types. This function
provides the necessities to embed an RGL scene in one.
}
\usage{
rglwidget(x = scene3d(minimal), width = figWidth(), height = figHeight(),
controllers = NULL,
elementId = NULL,
reuse = FALSE,
webGLoptions = list(preserveDrawingBuffer = TRUE),
shared = NULL, minimal = TRUE,
webgl, snapshot,
shinyBrush = NULL,
...,
oldConvertBBox = FALSE)
}
\arguments{
\item{x}{
An RGL scene produced by the \code{\link[rgl]{scene3d}} function.
}
\item{width, height}{
The width and height of the display in pixels.
}
\item{controllers}{Names of \code{\link{playwidget}} objects
associated with this scene, or objects (typically piped in). See Details below.
}
\item{snapshot,webgl}{Control of mode of display of scene.
See Details below.
}
\item{elementId}{The id to use on the HTML \code{div}
component that will hold the scene.
}
\item{reuse}{Ignored. See Details below.
}
\item{webGLoptions}{A list of options to pass
to WebGL when the drawing context is created. See the Details below.}
\item{shared}{An object produced by \code{\link{rglShared}}, or a list of such objects.}
\item{minimal}{Should attributes be skipped if they currently have
no effect? See \code{\link{scene3d}}.}
\item{shinyBrush}{The name of a Shiny \code{input} element
to receive information about mouse selections.}
\item{oldConvertBBox}{See Details below.}
\item{...}{Additional arguments
to pass to \code{htmlwidgets::\link{createWidget}}.}
}
\details{
This produces a WebGL version of an RGL scene using the \pkg{htmlwidgets}
framework. This allows display of the scene in the RStudio IDE, a browser, an \pkg{rmarkdown} document
or in a \pkg{shiny} app.
\code{options(rgl.printRglwidget = TRUE)} will cause
\code{rglwidget()} to be called and displayed
when the result of an RGL call that changes the
scene is printed.
In RMarkdown or in standalone code, you can use a \pkg{magrittr}-style
\dQuote{pipe} command to join an \code{rglwidget} with a
\code{\link{playwidget}} or \code{\link{toggleWidget}}. If the control widget comes
first, it should be piped into the \code{controllers}
argument. If the \code{rglwidget} comes first, it
can be piped into the first argument of \code{playwidget} or \code{toggleWidget}.
In earlier versions, the \code{reuse} argument let one output scene share data from earlier ones. This is no longer supported.
If \code{elementId} is \code{NULL} and we are not in a Shiny app,
\code{elementId} is set to a random value to facilitate re-use
of information.
To save the display to a file, use \code{htmlwidgets::\link{saveWidget}}.
This requires \command{pandoc} to be installed.
For a snapshot, you can use
\code{htmltools::save_html(img(src=rglwidget(snapshot=TRUE)), file = ...)}.
The \code{webGLoptions} argument is a list which will
be passed when the WebGL context is created. See
the WebGL 1.0 specification on \url{https://www.khronos.org/registry/webgl/specs/} for possible
settings. The default in \code{rglwidget} differs
from the WebGL default by setting \code{preserveDrawingBuffer = TRUE} in order to allow other tools to read
the image, but please note that some implementations
of WebGL contain bugs with this setting. We have
attempted to work around them, but may change our
default in the future if this proves unsatisfactory.
The \code{webgl} argument controls
whether a dynamic plot is displayed in HTML. In LaTeX
and some other formats
dynamic plots can't be
displayed, so if the \code{snapshot} argument is \code{TRUE},
\code{webgl} must be \code{FALSE}. (In previous versions
of the \pkg{rgl} package, both \code{webgl} and \code{snapshot} could be
\code{TRUE}; that hasn't worked for a while and is no longer
allowed as of version 0.105.6.)
The \code{snapshot} argument controls whether a snapshot is
displayed: it must be \code{!webgl} if both are specified.
Prior to \pkg{rgl} 0.106.21, \code{rglwidget} converted
bounding box decorations into separate objects: a box, text
for the labels, segments for the ticks. By default it now
generates these in Javascript, allowing axis labels to move as
they do in the display in \R. If you prefer the old conversion,
set \code{oldConvertBBox = TRUE}.
}
\section{Shiny specifics}{
This widget is designed to work with Shiny for interactive
displays linked to a server running R.
In a Shiny app, there will often be one or more
\code{\link{playwidget}} objects in the app, taking input from
the user. In order to be sure that the initial value of the user control
is reflected in the scene, you should list all players in the
\code{controllers} argument. See the sample application in
\code{system.file("shinyDemo", package = "rglwidget")} for an example.
In Shiny, it is possible to find out information about mouse selections
by specifying the name of an \code{input} item in the
\code{shinyBrush} argument. For example, with
\code{shinyBrush = "brush3d"}, each change
to the mouse selection will send data to \code{input$brush3d} in an
object of class \code{"rglMouseSelection"} with the
following components:
\describe{
\item{subscene}{The ID of the subscene where the mouse is selecting.}
\item{state}{Either \code{"changing"} or \code{"inactive"}.}
\item{region}{The coordinates of the corners of the selected region in the window,
in order \code{c(x1, y1, x2, y2)}.}
\item{model, proj, view}{The model matrix, projection matrix and viewport in effect at that location.}
}
This object can be used as the first argument to
\code{\link{selectionFunction3d}} to produce a test function for
whether a particular location is in the selected region. If the
brush becomes inactive, an object containing only the \code{state}
field will be sent, with value \code{"inactive"}.
}
\value{
An object of class \code{"htmlwidget"} (or \code{"shiny.tag.list"}
if pipes are used) that will intelligently print itself into
HTML in a variety of contexts including the R console, within R Markdown
documents, and within Shiny output bindings.
If objects are passed in the \code{shared} argument,
then the widget will respond to selection and filtering
applied to those as shared datasets. See \code{\link{rglShared}} for more details and an example.
}
\section{Appearance}{
The appearance of the display is set by the stylesheet
in \code{system.file("htmlwidgets/lib/rglClass/rgl.css")}.
The widget is of class \code{rglWebGL}, with id
set according to \code{elementId}. (As of this writing,
no special settings are given for class \code{rglWebGL},
but you can add your own.)
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{hook_webgl}} for an earlier approach to this problem. \code{\link{rglwidgetOutput}} for Shiny details.
}
\examples{
save <- getOption("rgl.useNULL")
options(rgl.useNULL=TRUE)
example("plot3d", "rgl")
widget <- rglwidget()
if (interactive() || in_pkgdown_example())
widget
\donttest{
if (interactive() && !in_pkgdown_example()) {
# Save it to a file. This requires pandoc
filename <- tempfile(fileext = ".html")
htmlwidgets::saveWidget(rglwidget(), filename)
browseURL(filename)
}
}
}
rgl/man/persp3d.deldir.Rd 0000644 0001762 0000144 00000005176 14145464133 014740 0 ustar ligges users \name{persp3d.deldir}
\alias{persp3d.deldir}
\alias{plot3d.deldir}
\alias{as.mesh3d.deldir}
\title{
Plot a Delaunay triangulation
}
\description{
The \code{\link[deldir]{deldir}()} function in the \pkg{deldir} package computes a Delaunay triangulation of a set
of points. These functions display it as a surface.
}
\usage{
\method{plot3d}{deldir}(x, ...)
\method{persp3d}{deldir}(x, ..., add = FALSE)
\method{as.mesh3d}{deldir}(x, col = "gray", coords = c("x", "y", "z"),
smooth = TRUE, normals = NULL, texcoords = NULL, ...)
}
\arguments{
\item{x}{
A \code{"deldir"} object, produced by the \code{\link[deldir]{deldir}()} function. It must contain \code{z} values.
}
\item{add}{
Whether to add surface to existing plot (\code{add = TRUE})
or create a new plot (\code{add = FALSE}, the default).
}
\item{col}{
Colors to apply to each vertex in the triangulation.
Will be recycled as needed.
}
\item{coords}{
See Details below.
}
\item{smooth}{
Whether to average normals at vertices for
a smooth appearance.
}
\item{normals}{
User-specified normals at each vertex. Requires \code{smooth = FALSE}.
}
\item{texcoords}{
Texture coordinates at each vertex.
}
\item{...}{
See Details below.
}
}
\details{
These functions construct a \code{\link{mesh3d}} object
corresponding to the triangulation in \code{x}. The
\code{plot3d} and \code{persp3d} methods plot it.
The \code{coords} parameter allows surfaces to be
plotted over any coordinate plane. It should be
a permutation of the column names \code{c("x", "y", "z")}
from the \code{"deldir"} object. The first will be used
as the x coordinate, the second as the y coordinate,
and the third as the z coordinate.
The \code{...} parameters in \code{plot3d.deldir}
are passed to \code{persp3d.deldir}; in \code{persp3d.deldir} they are
passed to both \code{as.mesh3d.deldir} and \code{persp3d.mesh3d};
in \code{as.mesh3d.deldir} they are used as material parameters
in a \code{\link{tmesh3d}} call.
}
\examples{
x <- rnorm(200, sd = 5)
y <- rnorm(200, sd = 5)
r <- sqrt(x^2 + y^2)
z <- 10 * sin(r)/r
col <- cm.colors(20)[1 + round(19*(z - min(z))/diff(range(z)))]
save <- options(rgl.meshColorWarning = FALSE)
# This code is awkward: to work with demo(rglExamples),
# we need auto-printing of the plots. This means we
# have to repeat the test for deldir.
haveDeldir <- checkDeldir()
if (haveDeldir) {
dxyz <- deldir::deldir(x, y, z = z, suppressMsge = TRUE)
persp3d(dxyz, col = col)
}
if (haveDeldir) {
open3d()
# Do it without smoothing and with a different orientation.
persp3d(dxyz, col = col, coords = c("z", "x", "y"), smooth = FALSE)
}
options(save)
}
\keyword{graphics}
rgl/man/rgl.setAxisCallback.Rd 0000644 0001762 0000144 00000005254 14137472630 015735 0 ustar ligges users \name{rgl.setAxisCallback}
\alias{rgl.setAxisCallback}
\alias{rgl.getAxisCallback}
\title{
User-defined axis labelling callbacks.
}
\description{
These are low level functions to set or get user-defined axis labelling callbacks in R.
}
\usage{
rgl.setAxisCallback(axis, draw = NULL,
dev = cur3d(), subscene = currentSubscene3d(dev))
rgl.getAxisCallback(axis, dev = cur3d(), subscene = currentSubscene3d(dev))
}
\arguments{
\item{axis}{
Which axis? Can be value from \code{1:3}.
}
\item{draw}{
The function to draw the axis. See Details below.
}
\item{dev, subscene}{
The RGL device and subscene to work with.
}
}
\details{
This function only works if a bounding box decoration
(set by \code{\link{bbox3d}}, for example) exists. When it
tries to label the axis specified in \code{rgl.setAxisCallback},
it will call \code{draw}, which is assumed to be a function
with header \code{function(margin)}.
The \code{margin}
argument will be a single string like \code{"x++"}, indicating
that RGL is drawing the x axis, and suggests putting it on the
edge represented by the high values of the other two axes.
The function may use \code{\link{par3d}("bbox")} to determine
the current size of the bounding box and should draw an
appropriate axis. See \code{\link{mtext3d}} for a discussion
of drawing in the margins.
The box outlining the plot region will always be drawn, but
can be made invisible by setting \code{front = "cull", back = "cull"} in the call to \code{\link{bbox3d}}.
}
\value{
Called for the side effect of setting the callback. The set
function returns
\code{NULL} invisibly.
}
\seealso{\code{\link{setAxisCallbacks}} to
work with \code{\link{rglwidget}}.
}
\author{
Duncan Murdoch
}
\examples{
datelabels <- local({
id <- 0
bbox <- NULL
function(margin) {
# Only need to redraw when the bbox changes
if (!identical(bbox, par3d("bbox"))) {
if (id > 0)
pop3d(id = id)
axis <- match(substr(margin, 1, 1), c("x", "y", "z"))
range <- as.Date(par3d("bbox")[2*axis + (-1):0],
origin = "1970-01-01")
where <- pretty(range)
where <- where[range[1] <= where & where <= range[2]]
id <<- mtext3d(format(where, format="\%b \%d"), margin, at = where, line = 1)
bbox <<- par3d("bbox")
}
}
})
# This doesn't work in WebGL displays
if (!in_pkgdown_example()) {
xyz <- cbind(Sys.Date() + rnorm(10, mean = 10),
rnorm(10), rnorm(10))
open3d()
# The default plots dates numerically:
plot3d(xyz, xlab = "Date", ylab = "y", zlab = "z")
rgl.setAxisCallback(1, datelabels)
# Repeat the data 5 days later
points3d(xyz + rep(c(5, 0, 0), each = 10))
# Make the plot square again
aspect3d(1,1,1)
}
}
rgl/man/light.Rd 0000644 0001762 0000144 00000005105 14145447077 013225 0 ustar ligges users \name{light}
\alias{rgl.light}
\alias{light3d}
\title{Add light source}
\description{
add a light source to the scene.
}
\usage{
light3d(theta = 0, phi = 15, x = NULL, ...)
rgl.light( theta = 0, phi = 0, viewpoint.rel = TRUE, ambient = "#FFFFFF",
diffuse = "#FFFFFF", specular = "#FFFFFF", x = NULL, y = NULL, z = NULL)
}
\arguments{
\item{theta, phi}{polar coordinates, used by default}
\item{viewpoint.rel}{logical, if TRUE light is a viewpoint light that is positioned relative to the current viewpoint}
\item{ambient, diffuse, specular }{ light color values used for lighting calculation }
\item{x, y, z}{cartesian coordinates, optional}
\item{...}{generic arguments passed through to RGL-specific (or other) functions}
}
\details{
Up to 8 light sources are supported. They are positioned either in
world space or relative to the camera. By providing polar
coordinates to theta and phi a directional light source is used. If
numerical values are given to x, y and z, a point-like light source with
finite distance to the objects in the scene is set up.
If \code{x} is non-null, \code{\link{xyz.coords}} will
be used to form the location values, so all three coordinates
can be specified in \code{x}.
See \code{\link{material3d}} for a discussion of how
the components of the light affect the display of objects.
}
\value{
This function is called for the side effect of adding a light. A light ID is
returned to allow \code{\link{pop3d}} to remove it.
}
\seealso{
\code{\link{rgl.clear}}
\code{\link{pop3d}}
}
\examples{
#
# a lightsource moving through the scene
#
data(volcano)
z <- 2 * volcano # Exaggerate the relief
x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N)
y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W)
zlim <- range(z)
zlen <- zlim[2] - zlim[1] + 1
colorlut <- terrain.colors(zlen) # height color lookup table
col <- colorlut[ z - zlim[1] + 1 ] # assign colors to heights for each point
open3d()
bg3d("gray50")
surface3d(x, y, z, color = col, back = "lines")
r <- max(y) - mean(y)
lightid <- spheres3d(1, 1, 1, alpha = 0)
frame <- function(time) {
a <- pi*(time - 1)
save <- par3d(skipRedraw = TRUE)
clear3d(type = "lights")
pop3d(id = lightid)
xyz <- matrix(c(r*sin(a) + mean(x), r*cos(a) + mean(y), max(z)), ncol = 3)
light3d(x = xyz, diffuse = "gray75",
specular = "gray75", viewpoint.rel = FALSE)
light3d(diffuse = "gray10", specular = "gray25")
lightid <<- spheres3d(xyz, emission = "white", radius = 4)
par3d(save)
Sys.sleep(0.02)
NULL
}
play3d(frame, duration = 2)
}
\keyword{dynamic}
rgl/man/matrices.Rd 0000644 0001762 0000144 00000011030 14145464133 013707 0 ustar ligges users \name{matrices}
\alias{matrices}
\alias{identityMatrix}
\alias{scaleMatrix}
\alias{translationMatrix}
\alias{rotationMatrix}
\alias{scale3d}
\alias{translate3d}
\alias{rotate3d}
\alias{transform3d}
\alias{asHomogeneous}
\alias{asEuclidean}
\alias{asHomogeneous2}
\alias{asEuclidean2}
\title{Work with homogeneous coordinates }
\description{
These functions construct 4x4 matrices for transformations
in the homogeneous coordinate system used by OpenGL, and translate
vectors between homogeneous and Euclidean coordinates.
}
\usage{
identityMatrix()
scaleMatrix(x, y, z)
translationMatrix(x, y, z)
rotationMatrix(angle, x, y, z, matrix)
asHomogeneous(x)
asEuclidean(x)
asHomogeneous2(x)
asEuclidean2(x)
scale3d(obj, x, y, z, ...)
translate3d(obj, x, y, z, ...)
rotate3d(obj, angle, x, y, z, matrix, ...)
transform3d(obj, matrix, ...)
}
\arguments{
\item{x, y, z, angle, matrix}{See details}
\item{obj}{An object to be transformed}
\item{...}{Additional parameters to be passed to methods}
}
\details{
OpenGL uses homogeneous coordinates to handle perspective and affine
transformations. The homogeneous point \code{(x, y, z, w)} corresponds
to the Euclidean point \code{(x/w, y/w, z/w)}. The matrices produced by
the functions \code{scaleMatrix}, \code{translationMatrix}, and \code{rotationMatrix}
are to be left-multiplied by a row vector
of homogeneous coordinates; alternatively, the transpose of the result
can be right-multiplied by a column vector. The generic functions
\code{scale3d}, \code{translate3d} and \code{rotate3d} apply these transformations
to the \code{obj} argument. The \code{transform3d} function is a synonym
for \code{rotate3d(obj, matrix = matrix)}.
By default, it is assumed that \code{obj} is a row vector
(or a matrix of row vectors) which will be multiplied on the right by
the corresponding matrix, but users may write methods for these generics
which operate differently. Methods are supplied for \code{\link{mesh3d}}
objects.
To compose transformations, use matrix multiplication. The effect is
to apply the matrix on the left first, followed by the one on the right.
\code{identityMatrix} returns an identity matrix.
\code{scaleMatrix} scales each coordinate by the given factor. In Euclidean
coordinates, \code{(u, v, w)} is transformed to \code{(x*u, y*v, z*w)}.
\code{translationMatrix} translates each coordinate by the given translation, i.e.
\code{(u, v, w)} is transformed to \code{(u + x, v + y, w + z)}.
\code{rotationMatrix} can be called in three ways. With
arguments \code{angle, x, y, z} it represents a rotation
of \code{angle} radians about the axis
\code{x, y, z}. If \code{matrix} is a 3x3 rotation matrix,
it will be converted into the corresponding matrix in 4x4 homogeneous
coordinates. Finally, if a 4x4 matrix is given, it will be returned unchanged.
(The latter behaviour is used to allow \code{transform3d} to act like a
generic function, even though it is not.)
Use \code{asHomogeneous(x)} to convert the Euclidean vector \code{x} to
homogeneous coordinates, and \code{asEuclidean(x)} for the reverse transformation. These functions accept the following
inputs:
\itemize{
\item n x 3 matrices: rows are assumed to be Euclidean
\item n x 4 matrices: rows are assumed to be homogeneous
\item vectors of length 3n or 4n: assumed to be vectors
concatenated. For the ambiguous case
of vectors that are length 12n (so both 3n and 4n are possible),
the assumption is that the conversion is necessary: \code{asEuclidean} assumes the vectors are homogeneous,
and \code{asHomogeneous} assumes the vectors are Euclidean.
}
Outputs are n x 4 or n x 3 matrices for \code{asHomogeneous}
and \code{asEuclidean} respectively.
The functions \code{asHomogeneous2} and \code{asEuclidean2}
act similarly, but they assume inputs are 3 x n or 4 x n
and outputs are in similar shapes.
}
\value{
\code{identityMatrix},
\code{scaleMatrix}, \code{translationMatrix}, and \code{rotationMatrix} produce
a 4x4 matrix representing the requested transformation
in homogeneous coordinates.
\code{scale3d}, \code{translate3d} and \code{rotate3d} transform the object
and produce a new object of the same class.
}
\author{ Duncan Murdoch }
\seealso{\code{\link{par3d}} for a description of how RGL uses matrices in
rendering.}
\examples{
# A 90 degree rotation about the x axis:
rotationMatrix(pi/2, 1, 0, 0)
# Find what happens when you rotate (2, 0, 0) by 45 degrees about the y axis:
x <- asHomogeneous(c(2, 0, 0))
y <- x \%*\% rotationMatrix(pi/4, 0, 1, 0)
asEuclidean(y)
# or more simply...
rotate3d(c(2, 0, 0), pi/4, 0, 1, 0)
}
\keyword{ dynamic }
rgl/man/mergeVertices.Rd 0000644 0001762 0000144 00000003012 14100762640 014700 0 ustar ligges users \name{mergeVertices}
\alias{mergeVertices}
\title{
Merge duplicate vertices in mesh object
}
\description{
A mesh object can have the same vertex listed twice. Each copy is
allowed to have separate normals, texture coordinates, and color.
However, it is more efficient to have just a single copy if those
differences aren't needed. For automatic smoothing using
\code{\link{addNormals}}, triangles and quads need to share vertices.
This function merges identical (or similar) vertices to achieve this.
}
\usage{
mergeVertices(mesh,
notEqual = NULL,
attribute = "vertices",
tolerance = sqrt(.Machine$double.eps))
}
\arguments{
\item{mesh}{
A \code{\link{mesh3d}} object.
}
\item{notEqual}{
A logical matrix indicating that certain pairs should not be merged
even if they appear identical.
}
\item{attribute}{
Which attribute(s) should be considered in comparing vertices?
A vector chosen from \code{c("vertices", "colors", "normals", "texcoords"))}
}
\item{tolerance}{
When comparing vertices using \code{\link{all.equal}}, this tolerance
will be used to ignore rounding error.
}
}
\value{
A new mesh object.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{as.mesh3d.rglId}}, which often constructs mesh
objects containing a lot of duplication.
}
\examples{
open3d()
(mesh1 <- cuboctahedron3d(col = rainbow(14), meshColor = "face"))
id <- shade3d(mesh1)
(mesh2 <- as.mesh3d(id))
shade3d(translate3d(mesh2, 3, 0, 0))
(mesh3 <- mergeVertices(mesh2))
shade3d(translate3d(mesh3, 6, 0, 0))
}
rgl/man/playwidget.Rd 0000644 0001762 0000144 00000013500 14100762641 014251 0 ustar ligges users \name{playwidget}
\alias{playwidget}
\title{
Add a widget to play animations
}
\description{
This is a widget that can be put in a web page to allow
animations with or without Shiny.
}
\usage{
playwidget(sceneId, controls,
start = 0, stop = Inf, interval = 0.05, rate = 1,
components = c("Reverse", "Play", "Slower", "Faster",
"Reset", "Slider", "Label"),
loop = TRUE,
step = 1, labels = NULL,
precision = 3,
elementId = NULL, respondTo = NULL,
reinit = NULL,
buttonLabels = components, pause = "Pause",
height = 40,
...)
}
\arguments{
\item{sceneId}{
The HTML id of the RGL scene being controlled,
or an object. See the Details below.
}
\item{controls}{
A single \code{"rglControl"} object, e.g. \code{\link{propertyControl}}, or a list of several.
}
\item{start, stop}{
The starting and stopping values of the animation. If
\code{labels} is supplied \code{stop} will default to step
through the labels.
}
\item{interval}{
The requested interval (in seconds) between updates. Updates
may occur at longer intervals.
}
\item{rate}{
The number of units of \dQuote{nominal} time per real world
second.
}
\item{components}{
Which components should be displayed? See Details below.
}
\item{loop}{
When the player reaches the end of the interval,
should it loop back to the beginning?
}
\item{step}{
Step size in the slider.
}
\item{labels}{
Optional labels to use, corresponding to slider steps. Set to
\code{NULL} for auto-generated labels.
}
\item{precision}{
If \code{labels=NULL}, the precision to use when displaying
timer values.
}
\item{elementId}{
The HTML id of the generated widget, containing buttons,
slider, etc.
}
\item{respondTo}{
The HTML ID of a Shiny input control (e.g. a \code{\link[shiny]{sliderInput}}
control) to respond to.}
\item{reinit}{
A vector of ids that will need re-initialization before
being drawn again.
}
\item{buttonLabels, pause}{
These are the labels that will be shown on the buttons if they are displayed. \code{pause} will
be shown on the \code{"Play"} button while playing.
}
\item{height}{
The height of the widget in pixels. In a pipe, this is a relative height.
}
\item{...}{Additional arguments to pass to
to \code{htmlwidgets::\link{createWidget}}.}
}
\details{
The \code{components} are buttons to control the animation,
a slider for manual control, and a label to show the current
value. They will be displayed in the order given in \code{components}. Not all need be included.
The buttons have the following behaviour:
\describe{
\item{Reverse}{Reverse the direction.}
\item{Play}{Play the animation.}
\item{Slower}{Decrease the playing speed.}
\item{Faster}{Increase the playing speed.}
\item{Reset}{Stop the animation and reset to the start value.}
}
If \code{respondTo} is used, no \code{components} are shown, as it is assumed Shiny (or whatever control is being referenced) will provide the UI components.
The \code{sceneId} component can be another \code{playwidget}, a \code{\link{rglwidget}} result, or a result of
\code{htmltools::\link[htmltools:builder]{tags}} or \code{htmltools::\link[htmltools:tag]{tagList}}. This allows you
to use a \pkg{magrittr}-style
\dQuote{pipe} command to join an \code{rglwidget} with one or more \code{\link{playwidget}}s. If a \code{playwidget} comes
first, \code{sceneId} should be set to \code{NA}. If
the \code{\link{rglwidget}} does not come first,
previous values should be piped into its \code{controllers}
argument. Other HTML code (including other widgets)
can be used in the chain if wrapped in \code{htmltools::\link[htmltools:tag]{tagList}}.
}
\section{Appearance}{
The appearance of the controls is set by the stylesheet
in \code{system.file("htmlwidgets/lib/rglClass/rgl.css")}.
The overall widget is of class \code{rglPlayer}, with id
set according to \code{elementId}.
The buttons are of HTML class \code{rgl-button}, the
slider is of class \code{rgl-slider}, and the label is of
class \code{rgl-label}. Each element has an id prefixed
by the widget id, e.g. \code{elementId-button-Reverse},
\code{elementId-slider}, etc. (where \code{elementId}
should be replaced by the actual id).
The \code{reinit} parameter handles the case where
an object needs re-initialization after each change. For
example, plane objects may need this if their intersection
with the bounding box changes shape. Note that
re-initialization is generally incompatible with
the \code{\link{vertexControl}} as it modifies values
which are set during initialization.
}
\value{
A widget suitable for use in an \pkg{Rmarkdown}-generated web
page, or elsewhere.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{subsetControl}},
\code{\link{propertyControl}}, \code{\link{ageControl}} and
\code{\link{vertexControl}} are possible controls to use.
\code{\link{toggleWidget}} is a wrapper for
\code{playwidget} and \code{\link{subsetControl}}
to insert a single button to toggle some elements in a display.
}
\examples{
saveopts <- options(rgl.useNULL = TRUE)
objid <- plot3d(1:10, 1:10, rnorm(10), col=c("red", "red"), type = "s")["data"]
control <- ageControl(value=0,
births=1:10,
ages = c(-5,0,5),
colors = c("green", "yellow", "red"),
objids = objid)
\donttest{
# This example uses explicit names
rglwidget(elementId = "theplot", controllers = "theplayer",
height = 300, width = 300)
playwidget("theplot", control, start = -5, stop = 5,
rate = 3, elementId = "theplayer",
components = c("Play", "Slider"))
}
# This example uses pipes, and can skip the names
widget <- rglwidget(height = 300, width = 300) \%>\%
playwidget(control, start = -5, stop = 5,
rate = 3, components = c("Play", "Slider"))
if (interactive() || in_pkgdown_example())
widget
options(saveopts)
}
rgl/man/persp3d.Rd 0000644 0001762 0000144 00000013376 14146471736 013507 0 ustar ligges users \name{persp3d}
\alias{persp3d}
\alias{persp3d.default}
\title{ Surface plots }
\description{
This function draws plots of surfaces in 3-space. \code{persp3d} is a generic function.}
\usage{
persp3d(x, \dots)
\method{persp3d}{default}(x = seq(0, 1, len = nrow(z)), y = seq(0, 1, len = ncol(z)), z,
xlim = NULL, ylim = NULL, zlim = NULL,
xlab = NULL, ylab = NULL, zlab = NULL, add = FALSE, aspect = !add,
forceClipregion = FALSE, ...)
}
\arguments{
\item{x, y, z}{points to plot on surface. See Details below.}
\item{xlim, ylim, zlim}{x-, y- and z-limits. If present,
the plot is clipped to this region.}
\item{xlab, ylab, zlab}{titles for the axes. N.B. These must be
character strings; expressions are not accepted. Numbers will be
coerced to character strings.}
\item{add}{whether to add the points to an existing plot.}
\item{aspect}{either a logical indicating whether to adjust the aspect ratio, or a new ratio.}
\item{forceClipregion}{force a clipping region to be used,
whether or not limits are given.}
\item{\dots}{additional material parameters to be passed to \code{\link{surface3d}}
and \code{\link{decorate3d}}.}
}
\details{
The default method plots a surface defined as a grid of \code{(x,y,z)} locations in space. The grid may be specified in several ways:
\itemize{
\item{As with \code{\link[graphics]{persp}}, \code{x} and \code{y} may be given as vectors in ascending order, with \code{z} given as a matrix. There
should be one \code{x} value for each row of \code{z} and
one \code{y} value for each column. The surface drawn will
have \code{x} constant across rows and \code{y} constant
across columns. This is the most convenient format when
\code{z} is a function of \code{x} and \code{y} which are
measured on a regular grid.}
\item{\code{x} and \code{y} may also be given as matrices, in which
case they should have the same dimensions as \code{z}. The
surface will combine corresponding points in each matrix
into locations \code{(x,y,z)} and draw the surface through those. This
allows general surfaces to be drawn, as in the example of a spherical Earth shown below.}
\item{If \code{x} is a \code{list}, its components \code{x$x}, \code{x$y} and \code{x$z} are used for \code{x}, \code{y} and
\code{z} respectively, though an explicitly specified
\code{z} value will have priority.}}
One difference from \code{\link[graphics]{persp}} is that colors are specified on each
vertex, rather than on each facet of the surface. To emulate the \code{\link[graphics]{persp}}
color handling, you need to do the following. First, convert the color vector to
an \code{(nx - 1)} by \code{(ny - 1)} matrix; then add an extra row before row 1,
and an extra column after the last column, to convert it to \code{nx} by \code{ny}.
(These extra colors will not be used). For example,
\code{col <- rbind(1, cbind(matrix(col, nx - 1, ny - 1), 1))}.
Finally, call \code{persp3d} with material property \code{smooth = FALSE}.
See the \dQuote{Clipping} section in \code{\link{plot3d}}
for more details on \code{xlim, ylim, zlim} and \code{forceClipregion}.
}
\value{
This function is called for the side effect of drawing the plot. A vector
of shape IDs is returned invisibly.
}
\author{Duncan Murdoch}
\seealso{\code{\link{plot3d}}, \code{\link{persp}}. There is
a \code{\link{persp3d.function}} method for drawing functions, and \code{\link{persp3d.deldir}} can be used
to draw surfaces defined by an irregular collection of points. A formula method \code{\link{persp3d.formula}} draws
surfaces using this method.
The \code{\link{surface3d}} function is used to draw the surface without the axes etc. }
\examples{
# (1) The Obligatory Mathematical surface.
# Rotated sinc function.
x <- seq(-10, 10, length = 20)
y <- x
f <- function(x, y) { r <- sqrt(x^2 + y^2); 10 * sin(r)/r }
z <- outer(x, y, f)
z[is.na(z)] <- 1
open3d()
# Draw the surface twice: the first draws the solid part,
# the second draws the grid. Offset the first so it doesn't
# obscure the lines.
persp3d(x, y, z, aspect = c(1, 1, 0.5), col = "lightblue",
xlab = "X", ylab = "Y", zlab = "Sinc( r )",
polygon_offset = 1)
persp3d(x, y, z, front = "lines", back = "lines",
lit = FALSE, add = TRUE)
highlevel() # trigger the plot
# (2) Add to existing persp plot:
xE <- c(-10, 10); xy <- expand.grid(xE, xE)
points3d(xy[, 1], xy[, 2], 6, col = "red")
lines3d(x, y = 10, z = 6 + sin(x), col = "green")
phi <- seq(0, 2*pi, len = 201)
r1 <- 7.725 # radius of 2nd maximum
xr <- r1 * cos(phi)
yr <- r1 * sin(phi)
lines3d(xr, yr, f(xr, yr), col = "pink", lwd = 2)
# (3) Visualizing a simple DEM model
z <- 2 * volcano # Exaggerate the relief
x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N)
y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W)
open3d()
invisible(bg3d("slategray")) # suppress display
material3d(col = "black")
persp3d(x, y, z, col = "green3", aspect = "iso",
axes = FALSE, box = FALSE)
# (4) A globe
lat <- matrix(seq(90, -90, len = 50)*pi/180, 50, 50, byrow = TRUE)
long <- matrix(seq(-180, 180, len = 50)*pi/180, 50, 50)
r <- 6378.1 # radius of Earth in km
x <- r*cos(lat)*cos(long)
y <- r*cos(lat)*sin(long)
z <- r*sin(lat)
open3d()
persp3d(x, y, z, col = "white",
texture = system.file("textures/worldsmall.png", package = "rgl"),
specular = "black", axes = FALSE, box = FALSE, xlab = "", ylab = "", zlab = "",
normal_x = x, normal_y = y, normal_z = z)
\dontrun{
# This looks much better, but is slow because the texture is very big
persp3d(x, y, z, col = "white",
texture = system.file("textures/world.png", package = "rgl"),
specular = "black", axes = FALSE, box = FALSE, xlab = "", ylab = "", zlab = "",
normal_x = x, normal_y = y, normal_z = z)
}
}
\keyword{ dynamic }
\keyword{ graphics }
rgl/man/viewpoint.Rd 0000644 0001762 0000144 00000004341 14100762641 014127 0 ustar ligges users \name{viewpoint}
\alias{rgl.viewpoint}
\alias{view3d}
\title{Set up viewpoint}
\description{
Set the viewpoint orientation.
}
\usage{
view3d( theta = 0, phi = 15, ...)
rgl.viewpoint( theta = 0, phi = 15, fov = 60, zoom = 1,
scale = par3d("scale"), interactive = TRUE, userMatrix,
type = c("userviewpoint", "modelviewpoint") )
}
\arguments{
\item{theta, phi}{polar coordinates}
\item{...}{additional parameters to pass to \code{rgl.viewpoint}}
\item{fov}{field-of-view angle in degrees}
\item{zoom}{zoom factor}
\item{scale}{real length 3 vector specifying the rescaling to apply to each axis}
\item{interactive}{logical, specifying if interactive navigation is allowed}
\item{userMatrix}{4x4 matrix specifying user point of view}
\item{type}{which viewpoint to set?}
}
\details{
The data model can be rotated using the polar coordinates \code{theta}
and \code{phi}. Alternatively, it can be set in a completely general way using the 4x4 matrix
\code{userMatrix}. If \code{userMatrix} is specified, \code{theta} and \code{phi} are ignored.
The pointing device of your graphics user-interface can also be used to
set the viewpoint interactively. With the pointing device the buttons are by default set as follows:
\describe{
\item{left}{adjust viewpoint position}
\item{middle}{adjust field of view angle}
\item{right or wheel}{adjust zoom factor}
}
The user's view can be set with \code{fov} and \code{zoom}.
If the \code{fov} angle is set to 0, a parallel or orthogonal
projection is used. Small non-zero values (e.g. 0.01 or less, but not
0.0) are likely to lead to rendering errors due to OpenGL limitations.
Prior to version 0.94, all of these characteristics were stored in
one viewpoint object. With that release the characteristics are split
into those that affect the projection (the user viewpoint) and those that
affect the model (the model viewpoint). By default, this function
sets both, but the \code{type} argument can be used to limit the effect.
}
\seealso{\code{\link{par3d}}}
\examples{
\dontrun{
# animated round trip tour for 10 seconds
rgl.open()
shade3d(oh3d(), color = "red")
start <- proc.time()[3]
while ((i <- 36*(proc.time()[3] - start)) < 360) {
rgl.viewpoint(i, i/4);
}
}
}
\keyword{dynamic}
rgl/man/expect_known_scene.Rd 0000644 0001762 0000144 00000003113 14100762640 015757 0 ustar ligges users \name{expect_known_scene}
\alias{expect_known_scene}
\title{
Helper for \pkg{testthat} testing.
}
\description{
Gets the current scene using \code{\link{scene3d}}, and
compares the result to a saved value, optionally closing
the window afterwards.
}
\usage{
expect_known_scene(name,
close = TRUE,
file = paste0("testdata/", name, ".rds"),
...)
}
\arguments{
\item{name}{
By default, the base name of the file to save results in.
Not used if \code{file} is specified.
}
\item{close}{
Whether to close the \pkg{rgl} window after the comparison.
}
\item{file}{
The file in which to save the result.
}
\item{...}{
Other arguments which will be passed to \code{\link[testthat]{expect_known_value}}.
}
}
\details{
This function uses \code{\link[testthat]{expect_known_value}}
to save a representation of the scene. During the comparison, the scene
is modified so that non-reproducible aspects are standardized
or omitted:
\itemize{
\item{object ids are changed to start at 1.}
\item{system-specific font names and texture names are deleted.}
\item{the window is shifted to the top left of the screen.}
}
Calls to \code{expect_known_scene()} enable \code{testthat::\link[testthat]{local_edition}(2)}
for the duration of the call, so it will work in \pkg{testthat} \dQuote{3rd edition}.
}
\value{
A value describing the changes to the saved object,
suitable for use in \code{\link[testthat]{test_that}()}.
}
\examples{
\dontrun{
# These lines can be included in testthat::test_that() code.
plot3d(1:10, 1:10, 1:10)
expect_known_scene("plot")
}
} rgl/man/GramSchmidt.Rd 0000644 0001762 0000144 00000002454 14100762640 014307 0 ustar ligges users \name{GramSchmidt}
\alias{GramSchmidt}
\title{
The Gram-Schmidt algorithm
}
\description{
Generate a 3x3 orthogonal matrix using the Gram-Schmidt algorithm.
}
\usage{
GramSchmidt(v1, v2, v3, order = 1:3)
}
\arguments{
\item{v1, v2, v3}{
Three length 3 vectors (taken as row vectors).
}
\item{order}{
The precedence order for the vectors; see Details.
}
}
\details{
This function orthogonalizes the matrix \code{rbind(v1, v2, v3)}
using the Gram-Schmidt algorithm. It can handle rank 2 matrices
(returning a rank 3 matrix). If the original is rank 1, it is likely
to fail.
The \code{order} vector determines the precedence of the original
vectors. For example, if it is \code{c(i, j, k)}, then row \code{i}
will be unchanged (other than normalization); row \code{j} will
normally be transformed within the span of rows \code{i} and \code{j}.
Row \code{k} will be transformed orthogonally to the span of
the others.
}
\value{
A 3x3 matrix whose rows are the orthogonalization of the original
row vectors.
}
\author{
Duncan Murdoch
}
\examples{
# Proceed through the rows in order
print(A <- matrix(rnorm(9), 3, 3))
GramSchmidt(A[1, ], A[2, ], A[3, ])
# Keep the middle row unchanged
print(A <- matrix(c(rnorm(2), 0, 1, 0, 0, rnorm(3)), 3, 3, byrow = TRUE))
GramSchmidt(A[1, ], A[2, ], A[3, ], order = c(2, 1, 3))
}
rgl/man/makeDependency.Rd 0000644 0001762 0000144 00000005561 14146450032 015022 0 ustar ligges users \name{makeDependency}
\alias{makeDependency}
\alias{RGL_DEBUGGING}
\title{
Process Javascript for HTML dependency
}
\description{
A utility function to help in development of internal
Javascript code, this function processes the Javascript
to minify it and report on errors and bad style.
}
\usage{
makeDependency(name, src, script = NULL, package,
version = packageVersion(package),
minifile = paste0(basename(src), ".min.js"),
debugging = FALSE, ...)
}
\arguments{
\item{name, src, script, package, version, ...}{
Arguments to pass to \code{htmltools::\link[htmltools]{htmlDependency}.}
}
\item{minifile}{Basename of minified file.}
\item{debugging}{
See details below.
}
}
\details{
This is a utility function used by RGL
to process its Javascript code used when displaying \code{\link{rglwidget}} values. It may be helpful in other packages to use
in their own installation.
If the \pkg{js} package version 1.2 or greater is installed,
the Javascript code will be minified and stored in the file named
by \code{minifile} in the \code{src} directory. Syntax errors
in the code will stop the process; unused variables will be
reported.
If \code{debugging} is \code{TRUE}, the locations of Javascript syntax
errors will be reported, along with hints about improvements,
and the original files will be used in the dependency object
that is created.
If \code{debugging} is \code{FALSE} (the default),
the minified file will be used in the dependency object,
hints won't be given, and syntax errors will lead to an
uninformative failure to minify.
}
\value{
An object that can be included in a list of dependencies passed to \code{htmltools::\link[htmltools:htmlDependencies]{attachDependencies}}.
}
\author{
Duncan Murdoch
}
\examples{
\dontrun{
# This is the code used to produce one of the dependencies
# for rglwidget().
# It writes to the system library copy of rgl so
# has been marked not to run in the example code.
makeDependency("rglwidgetClass",
src = "htmlwidgets/lib/rglClass",
script = c("rglClass.src.js",
"utils.src.js",
"buffer.src.js",
"subscenes.src.js",
"shaders.src.js",
"textures.src.js",
"projection.src.js",
"mouse.src.js",
"init.src.js",
"pieces.src.js",
"draw.src.js",
"controls.src.js",
"selection.src.js",
"rglTimer.src.js",
"pretty.src.js",
"axes.src.js"),
stylesheet = "rgl.css",
package = "rgl",
debugging = isTRUE(as.logical(Sys.getenv("RGL_DEBUGGING", "FALSE"))))
}
}
rgl/man/setGraphicsDelay.Rd 0000644 0001762 0000144 00000002372 14100762641 015340 0 ustar ligges users \name{setGraphicsDelay}
\alias{setGraphicsDelay}
\alias{RGL_SLOW_DEV}
\title{
Set a one-time slowdown on opening standard graphics
}
\description{
This function is mainly for internal use, to work around
a bug in macOS Catalina: if base plotting happens
too quickly after opening RGL and the first call to quartz, R crashes.
This inserts a delay after the first call to open the
graphics device. The default is
no delay, unless on Catalina with no graphics device
currently open but the \code{\link{quartz}} device set
as the default, when a 1 second delay will be added.
Use environment variable "RGL_SLOW_DEV = value" to set
a different default delay.
It works by changing the value of \code{\link{options}("device")},
so explicit calls to the device will not be affected.
It is called automatically when the \pkg{rgl} package is loaded.
}
\usage{
setGraphicsDelay(delay = Sys.getenv("RGL_SLOW_DEV", 0),
unixos = "none")
}
\arguments{
\item{delay}{
Number of seconds for the delay.
}
\item{unixos}{
The name of the Unix OS. If set to \code{"Darwin"},
and the version is 19.0.0 or greater, the default delay is
changed to 1 second.
}
}
\value{
Called for the side effect of adding the delay to the first
opening of the graphics device.
}
rgl/man/arc3d.Rd 0000644 0001762 0000144 00000006433 14100762640 013102 0 ustar ligges users \name{arc3d}
\alias{arc3d}
\title{
Draw arcs
}
\description{
Given starting and ending points on a sphere and the center of the
sphere, draw the
great circle arc between the starting and ending points. If
the starting and ending points have different radii, a segment of a
logarithmic spiral will join them.
}
\usage{
arc3d(from, to, center, radius, n, circle = 50, base = 0,
plot = TRUE, ...)
}
\arguments{
\item{from}{
One or more points from which to start arcs.
}
\item{to}{
One or more destination points.
}
\item{center}{
One or more center points.
}
\item{radius}{
If not missing, a vector of length \code{n} giving the
radii at each point between \code{from} and \code{to}.
If missing, the starting and ending points will be joined by
a logarithmic spiral.
}
\item{n}{
If not missing, how many segments to use between the first and last point. If missing, a value will be calculated based on the
angle between starting and ending points as seen from the center.
}
\item{circle}{
How many segments would be used if the arc went completely around
a circle.
}
\item{base}{
See Details below.
}
\item{plot}{
Should the arcs be plotted, or returned as a matrix?
}
\item{\dots}{
Additional parameters to pass to \code{\link{points3d}}.
}
}
\details{
If any of \code{from}, \code{to} or \code{center} is an n by 3
matrix with n > 1, multiple arcs will be drawn by recycling
each of these parameters to the number of rows of the longest
one.
If the vector lengths of \code{from - center} and
\code{to - center} differ, then instead of a spherical
arc, the function will draw a segment of a logarithmic spiral joining
the two points.
By default, the arc is drawn along the shortest great
circle path from \code{from} to \code{to}, but the
\code{base} parameter can be used to modify this.
If \code{base = 1} is used, the longer arc will be followed.
Larger positive integer values will result in \code{base - 1}
loops in that direction completely around the sphere.
Negative values will draw the curve in the same direction
as the shortest arc, but with \code{abs(base)} full loops.
It doesn't make much sense to ask for such loops unless
the radii of \code{from} and \code{to} differ, because
spherical arcs would overlap.
Normally the \code{base} parameter is left at its default
value of \code{0}.
When \code{base} is non-zero, the curve will be constructed in multiple
pieces, between \code{from}, \code{to}, \code{-from} and \code{-to},
for as many steps as necessary. If \code{n} is specified, it
will apply to each of these pieces.
}
\value{
If \code{plot = TRUE}, called mainly for the side effect of drawing arcs. Invisibly
returns the object ID of the collection of arcs.
If \code{plot = FALSE}, returns a 3 column matrix containing
the points that would be drawn as the arcs.
}
\author{
Duncan Murdoch
}
\examples{
normalize <- function(v) v/sqrt(sum(v^2))
# These vectors all have the same length
from <- t(apply(matrix(rnorm(9), ncol = 3), 1, normalize))
to <- normalize(rnorm(3))
center <- c(0, 0, 0)
open3d()
spheres3d(center, radius = 1, col = "white", alpha = 0.2)
arc3d(from, to, center, col = "red")
arc3d(from, 2*to, center, col = "blue")
text3d(rbind(from, to, center, 2*to),
text = c(paste0("from", 1:3), "to", "center", "2*to"),
depth_mask = FALSE, depth_test = "always")
}
rgl/man/rgl.texts.Rd 0000644 0001762 0000144 00000013571 14145464133 014046 0 ustar ligges users \name{rgl.texts}
\alias{rgl.texts}
\alias{rglFonts}
\title{
Low-level functions for plotting text
}
\description{
This is a low-level function for plotting text. Users
should normally use the high-level function \code{\link{text3d}} instead.
}
\usage{
rgl.texts(x, y = NULL, z = NULL, text,
adj = 0.5, pos = NULL, offset = 0.5,
family = par3d("family"), font = par3d("font"),
cex = par3d("cex"), useFreeType = par3d("useFreeType"), ...)
rglFonts(...)
}
\arguments{
\item{x, y, z}{point coordinates. Any reasonable way of defining the
coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}}
for details.}
\item{text}{text character vector to draw}
\item{adj}{ one value specifying the horizontal adjustment, or two,
specifying horizontal and vertical adjustment respectively, or three, specifying adjustment in all
three directions.}
\item{pos}{ a position specifier for the text. If specified, this
overrides any \code{adj} value given. Values of 0, 1, 2, 3, 4, 5 and 6 respectively indicate positions on, below, to the left of, above, to the right of, in front of and behind the specified coordinates.}
\item{offset}{ when \code{pos} is specified, this value gives the offset of the label from the specified coordinate in fractions of a character width.}
\item{ family }{A device-independent font family name, or "" }
\item{ font }{A numeric font number from 1 to 4 }
\item{ cex }{A numeric character expansion value }
\item{ useFreeType }{logical. Should FreeType be used to draw text? (See details below.)}
\item{ ... }{In \code{rgl.texts}, material properties; see \code{\link{rgl.material}} for details. In \code{rglFonts}, device dependent font definitions for use with FreeType.}
}
\details{
The \code{adj} parameter determines the position of the text relative to the
specified coordinate. Use \code{adj = c(0, 0)} to place the left bottom corner at
\code{(x, y, z)}, \code{adj = c(0.5, 0.5)} to center the text there, and \code{adj = c(1, 1)}
to put the right top corner there. All coordinates default to \code{0.5}.
Placement is done using the "advance" of
the string and the "ascent" of the font relative to the baseline, when these metrics
are known.
}
\section{Fonts}{
Fonts are specified using the \code{family}, \code{font}, \code{cex},
and \code{useFreeType} arguments. Defaults for the currently active
device may be set using \code{\link{par3d}}, or for future devices
using \code{\link{r3dDefaults}}.
The \code{family} specification is the same as for standard graphics, i.e.
families \cr
\code{c("serif", "sans", "mono", "symbol")} \cr
are normally
available, but users may add additional families. \code{font} numbers
are restricted to the range 1 to 4 for standard, bold, italic and bold italic
respectively. Font 5 is recoded as family \code{"symbol"}
font 1, but that is not supported unless specifically
installed, so should be avoided.
Using an unrecognized value for \code{"family"} will result in
the system standard font as used in RGL up to version 0.76. That font
is not resizable and \code{font} values are ignored.
If \code{useFreeType} is \code{TRUE}, then RGL will use the FreeType
anti-aliased fonts for drawing. This is generally desirable, and it is the
default on non-Windows systems if RGL was built to support FreeType.
FreeType fonts are specified using the \code{rglFonts} function. This function
takes a vector of four filenames of TrueType font files which
will be used for the four styles regular, bold, italic and bold italic. The
vector is passed with a name to be used as the family name, e.g.
\code{rglFonts(sans = c("/path/to/FreeSans.ttf", ...))}. In order to
limit the file size, the \pkg{rgl} package ships with just 3 font files, for
regular versions of the \code{serif}, \code{sans} and \code{mono} families.
Additional free font files were available in the past from the
Amaya project, though currently the
\code{\link{rglExtrafonts}} function provides an easier way
to register new fonts.
On Windows the system fonts are acceptable and are used
when \code{useFreeType = FALSE} (the current default in
\code{\link{r3dDefaults}}). Mappings to \code{family} names
are controlled by the \code{grDevices::windowsFonts()}
function.
Full pathnames should normally be used to specify font files. If relative
paths are used, they are interpreted differently by platform. Currently
Windows fonts are looked for in the Windows fonts folder, while other
platforms use the current working directory.
If FreeType fonts are not used, then bitmapped fonts will be used instead.
On Windows these will be based on the fonts specified using the
#ifdef windows
\code{\link{windowsFonts}}
#endif
#ifndef windows
\code{windowsFonts}
#endif
function, and are resizable.
Other platforms will use the default bitmapped font which is not
resizable.
Bitmapped fonts have a limited number of characters supported; if any
unsupported characters are used, an error will be thrown.
}
\value{
\code{rgl.texts} returns the object ID of the text object (or sprites, in case of \code{usePlotmath = TRUE})
invisibly.
\code{rglFonts} returns the current set of font definitions.
}
\examples{
\dontrun{
# These FreeType fonts are available from the Amaya project, and are not shipped
# with rgl. You would normally install them to the rgl/fonts directory
# and use fully qualified pathnames, e.g.
# system.file("fonts/FreeSerif.ttf", package = "rgl")
rglFonts(serif = c("FreeSerif.ttf", "FreeSerifBold.ttf", "FreeSerifItalic.ttf",
"FreeSerifBoldItalic.ttf"),
sans = c("FreeSans.ttf", "FreeSansBold.ttf", "FreeSansOblique.ttf",
"FreeSansBoldOblique.ttf"),
mono = c("FreeMono.ttf", "FreeMonoBold.ttf", "FreeMonoOblique.ttf",
"FreeMonoBoldOblique.ttf"),
symbol= c("ESSTIX10.TTF", "ESSTIX12.TTF", "ESSTIX9_.TTF",
"ESSTIX11.TTF"))
}
}
rgl/man/axes3d.Rd 0000644 0001762 0000144 00000015020 14137472630 013274 0 ustar ligges users \name{axes3d}
\alias{axes3d}
\alias{axis3d}
\alias{mtext3d}
\alias{title3d}
\alias{box3d}
\title{ Draw boxes, axes and other text outside the data }
\description{
These functions draw axes, boxes and text outside the range of the data.
\code{axes3d}, \code{box3d} and \code{title3d} are the higher level functions;
normally the others need not be called directly by users.
}
\usage{
axes3d(edges = "bbox", labels = TRUE, tick = TRUE, nticks = 5,
box = FALSE, expand = 1.03, ...)
box3d(...)
title3d(main = NULL, sub = NULL, xlab = NULL, ylab = NULL,
zlab = NULL, line = NA, level = NA, floating = NULL, ...)
axis3d(edge, at = NULL, labels = TRUE, tick = TRUE, line = 0,
pos = NULL, nticks = 5, ...)
mtext3d(text, edge, at = NULL, line = 0, level = 0,
floating = FALSE, pos = NA, ...)
}
\arguments{
\item{edges}{ a code to describe which edge(s) of the box to use; see Details below }
\item{labels}{ whether to label the axes, or (for \code{axis3d}) the
labels to use}
\item{tick}{ whether to use tick marks }
\item{nticks}{ suggested number of ticks }
\item{box}{ draw the full box if \code{"bbox"} axes are used }
\item{expand}{ how much to expand the box around the data }
\item{main}{ the main title for the plot }
\item{sub}{ the subtitle for the plot }
\item{xlab, ylab, zlab}{ the axis labels for the plot }
\item{line, level}{ the "line" of the plot margin to draw the label on, and "level" above or below it }
\item{floating}{ which mode of axis labels? One of
\code{TRUE}, \code{FALSE} or \code{NA}. (\code{NULL}
may also be used in \code{title3d} calls).
See Details for how these are handled.}
\item{edge, pos}{ the position at which to draw the axis or text }
\item{text}{ the text to draw }
\item{at}{ the value of a coordinate at which to draw the axis or labels. }
\item{\dots}{ additional parameters which are passed to \code{\link{bbox3d}} or \code{\link{material3d}} }
}
\details{
The rectangular prism holding the 3D plot has 12 edges. They are identified
using 3 character strings. The first character (`x', `y', or `z') selects
the direction of the axis. The next two characters are each `-' or `+',
selecting the lower or upper end of one of the other coordinates. If only
one or two characters are given, the remaining characters normally default to `-' (but with \code{mtext3d(..., floating = TRUE)} the default is `+'; see below).
For example \code{edge = 'x+'} draws an x-axis at the high level of y and the
low level of z.
By default, \code{axes3d} uses the \code{\link{bbox3d}} function to draw the axes.
The labels will move so that they do not obscure the data. Alternatively,
a vector of arguments as described above may be used, in which case
fixed axes are drawn using \code{axis3d}.
As of \pkg{rgl} version 0.106.21, axis drawing has changed
significantly. Text drawn in the margins
will
adapt to the margins (see \code{\link{bbox3d}}). The
\code{edge} and \code{floating} parameters will be recorded
in the \code{margin} and \code{floating} material
properties for the object.
If \code{floating = FALSE}, they will be drawn on the
specified edge.
If \code{floating = TRUE}, they will
move as the axis labels move when the scene is rotated.
The signs on the edge specification are interpreted as
agreeing with the axis ticks `+' or disagreeing `-'.
For example, \code{"x++"} will draw text on the x axis
in the same edge as the ticks, while \code{"x--"} will draw
on the opposite edge.
The final possible value for \code{floating} in \code{mtext3d} is
\code{NA}, which reproduces legacy \pkg{rgl}
behaviour. In
this case the labels are not tied to the bounding box,
so they should be drawn last, or they could appear inside
the box, overlapping the data.
In \code{title3d} \code{floating = NULL} (the default)
indicates the main title
and subtitle will be fixed while the axis labels will be
floating. The default locations for title and subtitle
are \code{line = 2} and
\code{level = 2} on edges \code{"x++"} and \code{"x--"}
respectively. The axis labels float at \code{line = 4} and \code{level = 1} on the same edge as the ticks.
The \code{at} parameter in \code{axis3d} is the location
of the ticks, defaulting to \code{\link{pretty}} locations.
In \code{mtext3d} the \code{at} parameter is the location
on the specified axis
at which to draw the text, defaulting to the middle of the
bounding box.
The \code{line} parameter is the line counting out
from the box in the same direction as the axis ticks,
and \code{level} is the line out in the orthogonal
direction. The ticks run from \code{line = 0} to \code{line = 1}, and the
tick labels are drawn at \code{line = 2}. Both are drawn at level 0.
The \code{pos} parameter is only supported in legacy mode. If it is a numeric vector of length 3, \code{edge} determines
the direction of the axis and the tick marks, and the values of the
other two coordinates in \code{pos} determine the position.
The \code{level} parameter is ignored in legacy mode.
For \code{mtext3d} in \code{floating = TRUE} or \code{floating = FALSE} mode,
there are 3 special values for the \code{at} parameter: it may
be \code{-Inf}, \code{NA} or \code{+Inf}, referring
to the bottom, middle or top of the given axis respectively.
}
\note{\code{mtext3d} is a wrapper for \code{\link{text3d}}
that sets the \code{margin} and \code{floating} material
properties. In fact, these properties can be set for many
kinds of objects (most kinds where it would make sense),
with the effect that the object will be drawn
in the margin, with \code{x} coordinate corresponding to
\code{at}, \code{y} corresponding to \code{line}, and \code{z}
corresponding to \code{level}.
}
\value{
These functions are called for their side effects. They return the object IDs of
objects added to the scene.
}
\author{ Duncan Murdoch }
\seealso{Classic graphics functions \code{\link{axis}}, \code{\link{box}},
\code{\link{title}}, \code{\link{mtext}}, and RGL function \code{\link{bbox3d}}.}
\examples{
open3d()
points3d(rnorm(10), rnorm(10), rnorm(10))
# First add standard axes
axes3d()
# and one in the middle (the NA will be ignored, a number would
# do as well)
axis3d('x', pos = c(NA, 0, 0))
# add titles
title3d('main', 'sub', 'xlab', 'ylab', 'zlab')
rgl.bringtotop()
open3d()
points3d(rnorm(10), rnorm(10), rnorm(10))
# Use fixed axes
axes3d(c('x', 'y', 'z'))
# Put 4 x-axes on the plot
axes3d(c('x--', 'x-+', 'x+-', 'x++'))
axis3d('x', pos = c(NA, 0, 0))
title3d('main', 'sub', 'xlab', 'ylab', 'zlab')
}
\keyword{dynamic}%-- one or more ...
rgl/man/vertexControl.Rd 0000644 0001762 0000144 00000006653 14145464133 014775 0 ustar ligges users \name{vertexControl}
\alias{vertexControl}
\title{
Set attributes of vertices
}
\description{
This is a function to produce actions in a web display. A
\code{\link{playwidget}} or Shiny
input control (e.g. a \code{\link[shiny]{sliderInput}} control)
sets a value which controls attributes of a selection of vertices.
}
\usage{
vertexControl(value = 0, values = NULL, vertices = 1, attributes,
objid = tagged3d(tag), tag,
param = seq_len(NROW(values)) - 1, interp = TRUE)
}
\arguments{
\item{value}{The value to use for input (typically \code{input$value}
in a Shiny app.) Not needed with \code{\link{playwidget}}.}
\item{values}{
A matrix of values, each row corresponding to an input value.
}
\item{vertices}{
Which vertices are being controlled? Specify \code{vertices} as a number from 1 to
the number of vertices in the \code{objid}.
}
\item{attributes}{A vector of attributes of a vertex,
from \code{c("x", "y", "z", "red", "green", "blue", "alpha", "nx", "ny", "nz",
"radii", "ox", "oy", "oz", "ts", "tt", "offset")}. See
Details.}
\item{objid}{
A single RGL object id.
}
\item{tag}{
An alternate way to specify \code{objid}.
}
\item{param}{
Parameter values corresponding to each row of \code{values}.
}
\item{interp}{
Whether to interpolate between rows of \code{values}.
}
}
\details{
This function
modifies attributes of vertices in a single
object. The \code{attributes} are properties of each vertex
in a scene; not all are applicable to all objects. In order,
they are: coordinates of the vertex \code{"x", "y", "z"}, color
of the vertex \code{"red", "green", "blue", "alpha"}, normal at the vertex
\code{"nx", "ny", "nz"}, radius of a sphere at the vertex
\code{"radius"}, origin within a texture \code{"ox", "oy"} and
perhaps \code{"oz"}, texture coordinates \code{"ts", "tt"}.
Planes are handled specially. The coefficients \code{a, b, c}
in the \code{\link{planes3d}} or \code{\link{clipplanes3d}}
specification are controlled
using \code{"nx", "ny", "nz"}, and \code{d} is handled as
\code{"offset"}. The \code{vertices} argument is interpreted
as the indices of the planes when these attributes are set.
If only one attribute of one vertex is specified, \code{values} may
be given as a vector and will be treated as a one-column matrix. Otherwise
\code{values} must be given as a matrix with \code{ncol(values) == max(length(vertices),
length(attributes))}. The \code{vertices} and \code{attributes} vectors will be recycled to the same length, and entries from column \code{j} of \code{values} will be applied to
vertex \code{vertices[j]}, attribute \code{attributes[j]}.
The \code{value} argument is translated into a row (or two rows if
\code{interp = TRUE}) of \code{values}
by finding its location in \code{param}.
}
\value{
A list of class \code{"rglControl"} of cleaned up parameter
values, to be used in an RGL widget.
}
\author{
Duncan Murdoch
}
\examples{
saveopts <- options(rgl.useNULL = TRUE)
theta <- seq(0, 6*pi, len=100)
xyz <- cbind(sin(theta), cos(theta), theta)
plot3d(xyz, type="l")
id <- spheres3d(xyz[1,,drop=FALSE], col="red")
widget <- rglwidget(width=500, height=300) \%>\%
playwidget(vertexControl(values=xyz,
attributes=c("x", "y", "z"),
objid = id, param=1:100),
start = 1, stop = 100, rate=10)
if (interactive() || in_pkgdown_example())
widget
options(saveopts)
}
rgl/man/select3d.Rd 0000644 0001762 0000144 00000004136 14100762641 013613 0 ustar ligges users \name{select3d}
\alias{select3d}
\alias{rgl.select3d}
\alias{selectionFunction3d}
\title{ Select a rectangle in an RGL scene }
\description{
This function allows the user to use the mouse to
select a region in an RGL scene.
}
\usage{
rgl.select3d(button = c("left", "middle", "right"),
dev = cur3d(), subscene = currentSubscene3d(dev))
select3d(...)
selectionFunction3d(proj, region = proj$region)
}
\arguments{
\item{ button }{ Which button to use for selection.}
\item{ dev, subscene}{ The RGL device and subscene to work with }
\item{ ... }{ Button argument to pass to \code{rgl.select3d}}
\item{proj}{An object returned from \code{\link{rgl.projection}}
containing details of the current projection.}
\item{region}{Corners of a rectangular region in the display.}
}
\details{
\code{select3d} and \code{rgl.select3d} select 3-dimensional regions by allowing the
user to use a mouse to draw a rectangle showing
the projection of the region onto the screen. They return
a function which tests points for inclusion in the selected region.
\code{selectionFunction3d} constructs such a test function given
coordinates and current transformation matrices.
If the scene is later moved or rotated, the selected region will
remain the same, though no longer corresponding to a rectangle on the screen.
}
\value{
All of these return a function \code{f(x, y, z)} which tests whether each
of the points \code{(x, y, z)} is in the selected region, returning
a logical vector. This function accepts input in a wide
variety of formats as it uses \code{\link[grDevices]{xyz.coords}}
to interpret its parameters.
}
\author{ Ming Chen / Duncan Murdoch }
\seealso{ \code{\link{selectpoints3d}}, \code{\link{locator}} }
\examples{
# Allow the user to select some points, and then redraw them
# in a different color
if (interactive()) {
x <- rnorm(1000)
y <- rnorm(1000)
z <- rnorm(1000)
open3d()
points3d(x, y, z)
f <- select3d()
if (!is.null(f)) {
keep <- f(x, y, z)
pop3d()
points3d(x[keep], y[keep], z[keep], color = 'red')
points3d(x[!keep], y[!keep], z[!keep])
}
}
}
\keyword{dynamic}
rgl/man/rgl-internal.Rd 0000644 0001762 0000144 00000002465 14100762641 014506 0 ustar ligges users \name{rgl-internal}
\title{Internal RGL functions and data}
\alias{rgl.bool}
\alias{rgl.numeric}
\alias{rgl.vertex}
\alias{rgl.nvertex}
\alias{rgl.color}
\alias{rgl.mcolor}
\alias{rgl.clamp}
\alias{rgl.attr}
\alias{rgl.enum}
\alias{rgl.enum.gl2ps}
\alias{rgl.enum.nodetype}
\alias{rgl.enum.pixfmt}
\alias{rgl.enum.polymode}
\alias{rgl.enum.textype}
\alias{rgl.enum.fogtype}
\alias{rgl.enum.primtype}
\alias{rgl.enum.texmagfilter}
\alias{rgl.enum.texminfilter}
\alias{rgl.selectstate}
\alias{rgl.setselectstate}
\alias{edgemap}
\alias{edgeindex}
\alias{cube3d.ib}
\alias{cube3d.vb}
\alias{oh3d.ib}
\alias{oh3d.vb}
\alias{dev3d}
\description{
Internal RGL functions
}
\usage{
rgl.bool(x)
rgl.numeric(x)
rgl.vertex(x, y = NULL, z = NULL)
rgl.nvertex(vertex)
rgl.color(color)
rgl.mcolor(colors)
rgl.clamp(value, low, high)
rgl.attr(vattr, nvertex)
rgl.enum(name, ..., multi = FALSE)
rgl.enum.gl2ps(postscripttype)
rgl.enum.nodetype(type)
rgl.enum.pixfmt(fmt)
rgl.enum.polymode(mode)
rgl.enum.textype(textype)
rgl.enum.fogtype(fogtype)
rgl.enum.primtype(primtype)
rgl.enum.texmagfilter(magfiltertype)
rgl.enum.texminfilter(minfiltertype)
rgl.selectstate(dev, subscene)
rgl.setselectstate(state, dev, subscene)
edgemap(size)
edgeindex(from, to, size, row, col)
}
\details{
These are not to be called by the user.
}
\keyword{internal}
rgl/man/r3d.Rd 0000644 0001762 0000144 00000007717 14100762641 012605 0 ustar ligges users \name{r3d}
\alias{r3d}
\title{Generic 3D interface}
\description{Generic 3D interface for 3D rendering and computational geometry.}
\details{
R3d is a design for an interface for 3d rendering and computation without dependency
on a specific rendering implementation. R3d includes a collection
of 3D objects and geometry algorithms.
All r3d interface functions are named \code{*3d}. They represent generic functions that delegate
to implementation functions.
The interface can be grouped into 8 categories: Scene Management, Primitive Shapes,
High-level Shapes, Geometry Objects, Visualization, Interaction, Transformation,
Subdivision.
The rendering interface gives an abstraction to the underlying rendering model. It can
be grouped into four categories:
\describe{
\item{Scene Management:}{A 3D scene consists of shapes, lights and background environment.}
\item{Primitive Shapes:}{Generic primitive 3D graphics shapes such as points, lines, triangles, quadrangles and texts.}
\item{High-level Shapes:}{Generic high-level 3D graphics shapes such as spheres, sprites and terrain.}
\item{Interaction:}{Generic interface to select points in 3D space using the pointer device.}
}
In this package we include an implementation of r3d using the underlying \code{rgl.*} functions.
3D computation is supported through the use of object structures that live entirely in R.
\describe{
\item{Geometry Objects:}{Geometry and mesh objects allow to define high-level geometry for computational purpose such as triangle or
quadrangle meshes (see \code{\link{mesh3d}}).}
\item{Transformation:}{Generic interface to transform 3d objects.}
\item{Visualization:}{Generic rendering of 3d objects such as dotted, wired or shaded.}
\item{Computation:}{Generic subdivision of 3d objects.}
}
At present, the main practical differences between the r3d functions
and the \code{rgl.*} functions are as follows.
The r3d functions call
\code{\link{open3d}} if there is no device open, and the
\code{rgl.*} functions call \code{\link{rgl.open}}. By default
\code{\link{open3d}} sets the initial orientation of the coordinate
system in 'world coordinates', i.e. a right-handed coordinate system
in which the x-axis increases from left to right, the y-axis
increases with depth into the scene, and the z-axis increases from
bottom to top of the screen. \code{rgl.*} functions, on the other
hand, use a right-handed coordinate system similar to that used in
OpenGL. The x-axis matches that of r3d, but the y-axis increases
from bottom to top, and the z-axis decreases with depth into the
scene. Since the user can manipulate the scene, either system can
be rotated into the other one.
The r3d functions also preserve the \code{rgl.material} setting across
calls (except for texture elements, in the current implementation), whereas
the \code{rgl.*} functions leave it as set by the last call.
The example code below illustrates the two coordinate systems.
}
\seealso{
\code{\link{points3d}},
\code{\link{lines3d}},
\code{\link{segments3d}},
\code{\link{triangles3d}},
\code{\link{quads3d}},
\code{\link{text3d}},
\code{\link{spheres3d}},
\code{\link{sprites3d}},
\code{\link{terrain3d}},
\code{\link{select3d}},
\code{\link{dot3d}},
\code{\link{wire3d}},
\code{\link{shade3d}},
\code{\link{transform3d}},
\code{\link{rotate3d}},
\code{\link{subdivision3d}},
\code{\link{mesh3d}},
\code{\link{cube3d}},
\code{\link{rgl}}
}
\examples{
x <- c(0, 1, 0, 0)
y <- c(0, 0, 1, 0)
z <- c(0, 0, 0, 1)
labels <- c("Origin", "X", "Y", "Z")
i <- c(1, 2, 1, 3, 1, 4)
# rgl.* interface
rgl.open()
rgl.texts(x, y, z, labels)
rgl.texts(1, 1, 1, "rgl.* coordinates")
rgl.lines(x[i], y[i], z[i])
# *3d interface
open3d()
text3d(x, y, z, labels)
text3d(1, 1, 1, "*3d coordinates")
segments3d(x[i], y[i], z[i])
}
\keyword{dynamic}
rgl/man/polygon3d.Rd 0000644 0001762 0000144 00000004227 14100762641 014024 0 ustar ligges users \name{polygon3d}
\alias{polygon3d}
\title{
Draw a polygon in three dimensions
}
\description{
This function takes a description of a flat polygon in x, y and z coordinates,
and draws it in three dimensions.
}
\usage{
polygon3d(x, y = NULL, z = NULL, fill = TRUE, plot = TRUE,
coords = 1:2, random = TRUE, ...)
}
\arguments{
\item{x, y, z}{
Vertices of the polygon in a form accepted by \code{\link{xyz.coords}}.
}
\item{fill}{
logical; should the polygon be filled?
}
\item{plot}{
logical; should the polygon be displayed?
}
\item{coords}{
Which two coordinates (\code{x = 1}, \code{y = 2}, \code{z = 3}) describe the
polygon.
}
\item{random}{
Should a random triangulation be used?
}
\item{\dots}{
Other parameters to pass to \code{\link{lines3d}} or \code{\link{shade3d}} if \code{plot = TRUE}.
}
}
\details{
The function triangulates the two dimensional polygon described by \code{coords}, then
applies the triangulation to all three coordinates. No check is made that the polygon
is actually all in one plane, but the results may be somewhat unpredictable
(especially if \code{random = TRUE}) if it is not.
Polygons need not be simple; use \code{NA} to indicate separate closed pieces. For
\code{fill = FALSE} there are no other restrictions on the pieces, but for
\code{fill = TRUE} the resulting two-dimensional polygon needs to be one that
\code{\link{triangulate}} can handle.
}
\value{
If \code{plot = TRUE}, the id number of the lines (for \code{fill = FALSE}) or triangles
(for \code{fill = TRUE}) that have been plotted.
If \code{plot = FALSE}, then for \code{fill = FALSE}, a vector of indices into
the XYZ matrix that could be used to draw the polygon. For \code{fill = TRUE},
a triangular mesh object representing the triangulation.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{extrude3d}} for a solid extrusion of a polygon, \code{\link{triangulate}} for
the triangulation.
}
\examples{
theta <- seq(0, 4*pi, len = 50)
r <- theta + 1
r <- c(r[-50], rev(theta*0.8) + 1)
theta <- c(theta[-50], rev(theta))
x <- r*cos(theta)
y <- r*sin(theta)
open3d()
plot(x, y, type = "n")
polygon(x, y)
polygon3d(x, y, x + y, col = "blue")
}
\keyword{ graphics }
rgl/man/planes.Rd 0000644 0001762 0000144 00000004457 14100762641 013375 0 ustar ligges users \name{planes3d}
\alias{planes3d}
\alias{clipplanes3d}
\title{Add planes}
\description{
\code{planes3d} adds mathematical planes
to a scene. Their intersection with the current
bounding box will be drawn. \code{clipplanes3d}
adds clipping planes to a scene.
}
\usage{
planes3d(a, b = NULL, c = NULL, d = 0, ...)
clipplanes3d(a, b = NULL, c = NULL, d = 0)
}
\arguments{
\item{a, b, c}{
Coordinates of the normal to the plane. Any reasonable way of defining the
coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}}
for details.
}
\item{d}{
Coordinates of the "offset". See the details.
}
\item{\dots}{
Material properties. See \code{\link{rgl.material}} for details.
}
}
\details{
\code{planes3d} draws planes using the parametrization
\eqn{a x + b y + c z + d = 0}. Multiple planes may be specified
by giving multiple values for any of \code{a, b, c, d}; the other
values will be recycled as necessary.
\code{clipplanes3d} defines clipping planes
using the same equations. Clipping planes suppress the display of
other objects (or parts of them) in the subscene, based on their coordinates.
Points (or parts of lines or surfaces) where the coordinates \code{x, y, z}
satisfy \eqn{a x + b y + c z + d < 0} will be suppressed.
The number of clipping planes
supported by the OpenGL driver is implementation dependent; use
\code{par3d("maxClipPlanes")} to find the limit.
}
\value{
A shape ID of the planes or clipplanes object is returned invisibly.
}
\seealso{
\code{\link{abclines3d}} for mathematical lines.
\code{\link{triangles3d}} or the corresponding
functions for quadrilaterals may be used to draw sections of planes that
do not adapt to the bounding box.
The example in \link{subscene3d} shows how to combine clipping planes
to suppress complex shapes.
}
\examples{
# Show regression plane with z as dependent variable
open3d()
x <- rnorm(100)
y <- rnorm(100)
z <- 0.2*x - 0.3*y + rnorm(100, sd = 0.3)
fit <- lm(z ~ x + y)
plot3d(x, y, z, type = "s", col = "red", size = 1)
coefs <- coef(fit)
a <- coefs["x"]
b <- coefs["y"]
c <- -1
d <- coefs["(Intercept)"]
planes3d(a, b, c, d, alpha = 0.5)
open3d()
ids <- plot3d(x, y, z, type = "s", col = "red", size = 1, forceClipregion = TRUE)
oldid <- useSubscene3d(ids["clipregion"])
clipplanes3d(a, b, c, d)
useSubscene3d(oldid)
}
\keyword{dynamic}
rgl/man/setAxisCallbacks.Rd 0000644 0001762 0000144 00000007347 14137472630 015342 0 ustar ligges users \name{setAxisCallbacks}
\alias{setAxisCallbacks}
\title{
User-defined axis labelling callbacks.
}
\description{
This function sets user callbacks to construct axes in R or
\code{\link{rglwidget}} displays.
}
\usage{
setAxisCallbacks(axes, fns,
javascript = NULL,
subscene = scene$rootSubscene$id,
scene = scene3d(minimal = FALSE),
applyToScene = TRUE,
applyToDev = missing(scene))
}
\arguments{
\item{axes}{
Which axes? Specify as number in \code{1:3} or letter in
\code{c("x", "y", "z")}.
}
\item{fns}{
Function or list of functions or character vector giving
names of functions.
}
\item{javascript}{
Optional block of Javascript code to be
included (at the global level).
}
\item{subscene}{
Which subscene do these callbacks apply to?
}
\item{scene}{
Which scene?
}
\item{applyToScene}{
Should these changes apply to the scene object?
}
\item{applyToDev}{
Should these changes apply to the current device?
}
}
\details{
If \code{applyToScene} is \code{TRUE}, this function adds Javascript
callbacks to the \code{scene} object.
If \code{applyToDev} is \code{TRUE}, it adds R
callbacks to the current RGL device.
For Javascript,
the callbacks are specified as strings; these will be
evaluated within the browser in the global context to define the functions,
which will then be called with the Javascript
\code{this} object set to the current
\code{rglwidgetClass} object.
For R, they may be strings or R functions.
Both options may be \code{TRUE}, in which case the
callbacks must be specified as strings which are
both valid Javascript and valid R. The usual way to
do this is to give just a function name, with the
function defined elsewhere, as in the Example below.
The functions should have a header of the form
\code{function(margin)}. The \code{margin} argument
will be a string like \code{"x++"} indicating which margin
would be chosen by R. If RGL would not choose to draw any
axis annotations (which happens with \code{\link{rglwidget}}, though
not currently in R itself), only the letter will be passed,
e.g. \code{"x"}.
}
\value{
Invisibly returns an \code{rglScene} object. This
object will record the changes if \code{applyToScene}
is \code{TRUE}.
If \code{applyToDev} is \code{TRUE}, it will also
have the side effect of attempting to install the
callbacks using \code{\link{rgl.setAxisCallback}}.
}
\seealso{
\code{\link{setUserCallbacks}} for mouse callbacks.
}
\author{
Duncan Murdoch
}
\examples{
# Draw arrows instead of tick marks on axes
arrowAxis <- local({
ids <- c(NA, NA, NA)
bbox <- c(NA, NA, NA, NA, NA, NA)
function(margin) {
dim <- if (grepl("x", margin)) 1 else
if (grepl("y", margin)) 2 else
3
inds <- 2*dim + (-1):0
range <- par3d("bbox")[inds]
if (!identical(bbox[inds], range)) {
if (!is.na(ids[dim]))
pop3d(id = ids[dim])
bbox[inds] <<- range
center <- mean(range)
from <- mean(c(range[1], center))
to <- mean(c(center, range[2]))
# margin should agree with suggestion, so use "x++" etc.
margin <- gsub("-", "+", margin)
ids[dim] <- arrow3d(p0 = c(from, 1, 1),
p1 = c(to, 1, 1),
n = 4,
type = "lines",
margin = margin,
floating = TRUE)
}
}
})
# Define the Javascript function with the same name to use in WebGL
# Since Javascript won't change the bounding box, this function
# doesn't need to do anything.
js <- "
window.arrowAxis = function(margin) {} ;
"
xyz <- matrix(rnorm(60), ncol = 3)
plot3d(xyz, xlab = "x", ylab = "y", zlab = "z")
setAxisCallbacks(1:3, "arrowAxis", javascript = js)
rglwidget()
}
rgl/man/mfrow3d.Rd 0000644 0001762 0000144 00000010342 14100762640 013461 0 ustar ligges users \name{mfrow3d}
\alias{mfrow3d}
\alias{layout3d}
\alias{next3d}
\alias{subsceneList}
\alias{clearSubsceneList}
\title{
Set up multiple figure layouts
}
\description{
The \code{mfrow3d} and \code{layout3d} functions provide functionality in RGL
similar to \code{\link{par}("mfrow")} and \code{\link{layout}} in classic R graphics.
}
\usage{
subsceneList(value, window = cur3d())
mfrow3d(nr, nc, byrow = TRUE, parent = NA, sharedMouse = FALSE, ...)
layout3d(mat, widths = rep.int(1, ncol(mat)),
heights = rep.int(1, nrow(mat)),
parent = NA, sharedMouse = FALSE,
...)
next3d(current = NA, clear = TRUE, reuse = TRUE)
clearSubsceneList(delete = currentSubscene3d() \%in\% subsceneList(),
window = cur3d())
}
\arguments{
\item{value}{
A new subscene list to set. If missing, return the current one (or \code{NULL}).
}
\item{window}{
Which window to operate on.
}
\item{nr, nc}{
Number of rows and columns of figures.
}
\item{byrow}{
Whether figures progress by row (as with \code{\link{par}("mfrow")}) or by column
(as with \code{\link{par}("mfcol")}).
}
\item{mat, widths, heights}{
Layout parameters; see \code{\link{layout}} for their interpretation.
}
\item{parent}{
The parent subscene. \code{NA} indicates the current subscene. See Details below.
}
\item{sharedMouse}{
Whether to make all subscenes \code{\link{par3d}("listeners")} to each other.
}
\item{\dots}{
Additional parameters to pass to \code{\link{newSubscene3d}} as each
subscene is created.
}
\item{current}{
The subscene to move away from. \code{NA} indicates the current subscene.
}
\item{clear}{
Whether the newly entered subscene should be cleared upon entry.
}
\item{reuse}{
Whether to skip advancing if the current subscene has no objects in it.
}
\item{delete}{
If \code{TRUE}, delete the subscenes in the current window.
}
}
\details{
rgl can maintain a list of subscenes; the \code{mfrow3d} and \code{layout3d} functions create that list.
When the list is in place, \code{next3d} causes RGL to move to the next scene in the list, or cycle
back to the first one.
Unlike the classic R graphics versions of these functions, these functions are completely compatible with
each other. You can mix them within a single RGL window.
In the default case where \code{parent} is missing, \code{mfrow3d} and \code{layout3d} will
call \code{clearSubsceneList()} at the start.
By default \code{clearSubsceneList()} checks
whether the current subscene is in the current subscene list; if so, it will delete
all subscenes in the list, and call \code{\link{gc3d}} to delete any objects that are no
longer shown. The subscene list will be set to a previous value if one was recorded,
or \code{NULL} if not.
If \code{parent} is specified in \code{mfrow3d} or \code{layout3d}
(even as \code{NA}), the new subscenes will be created within
the parent.
The \code{next3d()} function first finds out if the current
subscene is in the current list. If not, it moves to the
previous list, and looks there. Once it finds a list
containing the current subscene, it moves to the next entry
in that list. If it can't find one, it creates a length
one list containing just the current subscene.
}
\value{
\code{mfrow3d} and \code{layout3d} return a vector of subscene id values that have just been
created. If a previous subscene list was in effect and was not automatically cleared,
it is attached as an attribute \code{"prev"}.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{newSubscene3d}}, \code{\link{par}}, \code{\link{layout}}.
}
\examples{
shapes <- list(Tetrahedron = tetrahedron3d(), Cube = cube3d(), Octahedron = octahedron3d(),
Icosahedron = icosahedron3d(), Dodecahedron = dodecahedron3d(),
Cuboctahedron = cuboctahedron3d())
col <- rainbow(6)
open3d()
mfrow3d(3, 2)
for (i in 1:6) {
next3d() # won't advance the first time, since it is empty
shade3d(shapes[[i]], col = col[i])
}
highlevel(integer()) # To trigger display as rglwidget
open3d()
mat <- matrix(1:4, 2, 2)
mat <- rbind(mat, mat + 4, mat + 8)
layout3d(mat, height = rep(c(3, 1), 3), sharedMouse = TRUE)
for (i in 1:6) {
next3d()
shade3d(shapes[[i]], col = col[i])
next3d()
text3d(0, 0, 0, names(shapes)[i])
}
highlevel(integer())
}
\keyword{graphics }
rgl/man/persp3d.function.Rd 0000644 0001762 0000144 00000013133 14100762641 015306 0 ustar ligges users \name{persp3d.function}
\alias{plot3d.function}
\alias{persp3d.function}
\title{
Plot a function of two variables
}
\description{
Plot a function \code{z(x, y)} or a parametric function
\code{(x(s, t), y(s, t), z(s, t))}.
}
\usage{
\method{persp3d}{function}(x,
xlim = c(0, 1), ylim = c(0, 1),
slim = NULL, tlim = NULL,
n = 101,
xvals = seq.int(min(xlim), max(xlim), length.out = n[1]),
yvals = seq.int(min(ylim), max(ylim), length.out = n[2]),
svals = seq.int(min(slim), max(slim), length.out = n[1]),
tvals = seq.int(min(tlim), max(tlim), length.out = n[2]),
xlab, ylab, zlab,
col = "gray", otherargs = list(),
normal = NULL, texcoords = NULL, \dots)
\method{plot3d}{function}(x, \ldots)
}
\arguments{
\item{x}{
A function of two arguments. See the details below.
}
\item{xlim, ylim}{
By default, the range of x and y values. For a parametric
surface, if these are not missing, they are used as limits
on the displayed x and y values.
}
\item{slim, tlim}{
If not \code{NULL}, these give the range of s and t in the
parametric specification of the surface. If
only one is given, the other defaults to \code{c(0, 1)}.
}
\item{n}{
A one or two element vector giving the number of
steps in the x and y (or s and t) grid.
}
\item{xvals, yvals}{
The values at which to evaluate x and y. Ignored for
a parametric surface. If used, \code{xlim} and/or \code{ylim}
are ignored.
}
\item{svals, tvals}{
The values at which to evaluate s and t for a parametric
surface. Only used if
\code{slim} or \code{tlim} is not \code{NULL}. As with
\code{xvals} and \code{yvals}, these override the corresponding
\code{slim} or \code{tlim} specification.
}
\item{xlab, ylab, zlab}{
The axis labels. See the details below for the defaults.
}
\item{col}{
The color to use for the plot. See the details below.
}
\item{otherargs}{
Additional arguments to pass to the function.
}
\item{normal, texcoords}{
Functions to set surface normals or texture coordinates. See
the details below.
}
\item{\dots}{
Additional arguments to pass to \code{\link{persp3d}}.
}
}
\details{
The \code{"function"} method for \code{plot3d} simply passes
all arguments to \code{persp3d}. Thus this description applies
to both.
The first argument \code{x} is required to be a function. It
is named \code{x} only because of the requirements of the S3
system; in the remainder of this help page, we will assume
that the assignment \code{f <- x} has been made, and will
refer to the function \code{f()}.
\code{persp3d.function} evaluates \code{f()} on a two-dimensional
grid of values, and displays the resulting surface. The values
on the grid will be passed in as vectors in the
first two arguments to the function, so \code{f()} needs
to be vectorized. Other optional arguments to \code{f()}
can be specified in the \code{otherargs} list.
In the default form where \code{slim} and \code{tlim} are both
\code{NULL}, it is assumed that \code{f(x, y)} returns heights,
which will be plotted in the z coordinate. The default axis labels
will be taken from the argument names to \code{f()} and the
expression passed as argument \code{x} to this function.
If \code{slim} or \code{tlim} is specified, a parametric
surface is plotted. The function
\code{f(s, t)} must return a 3-column matrix, giving x, y and z
coordinates of points on the surface. The default axis
labels will be the column names if those are present.
In this case \code{xlim}, \code{ylim} and \code{zlim}
are used to define a clipping region only if specified;
the defaults are ignored.
The color of the surface may be specified as the name of a
color, or a vector or matrix of color names. In this case
the colors will be recycled across the points on the grid
of values.
Alternatively, a function may be given: it should be a function
like \code{\link{rainbow}} that takes an integer argument and
returns a vector of colors. In this case the colors are mapped
to z values.
The \code{normal} argument allows specification of a function
to compute normal vectors to the surface. This function is
passed the same arguments as \code{f()} (including \code{otherargs}
if present), and should produce a 3-column matrix containing the
x, y and z coordinates of the normals.
The \code{texcoords} argument is a function similar to \code{normal}, but
it produces a 2-column matrix containing texture coordinates.
Both \code{normal} and \code{texcoords} may also contain matrices,
with 3 and 2 columns respectively, and rows corresponding to the
points that were passed to \code{f()}.
}
\value{
This function constructs a call to \code{\link{persp3d}}
and returns the value from that function.
}
\author{
Duncan Murdoch
}
\seealso{
The \code{\link{curve}} function in base graphics does
something similar for functions of one variable. See the
example below for space curves.
}
\examples{
# (1) The Obligatory Mathematical surface.
# Rotated sinc function, with colors
f <- function(x, y) {
r <- sqrt(x^2 + y^2)
ifelse(r == 0, 10, 10 * sin(r)/r)
}
open3d()
plot3d(f, col = colorRampPalette(c("blue", "white", "red")),
xlab = "X", ylab = "Y", zlab = "Sinc( r )",
xlim = c(-10, 10), ylim = c(-10, 10),
aspect = c(1, 1, 0.5))
# (2) A cylindrical plot
f <- function(s, t) {
r <- 1 + exp( -pmin( (s - t)^2,
(s - t - 1)^2,
(s - t + 1)^2 )/0.01 )
cbind(r*cos(t*2*pi), r*sin(t*2*pi), s)
}
open3d()
plot3d(f, slim = c(0, 1), tlim = c(0, 1), col = "red", alpha = 0.8)
# Add a curve to the plot, fixing s at 0.5.
plot3d(f(0.5, seq.int(0, 1, length.out = 100)), type = "l", add = TRUE,
lwd = 3, depth_test = "lequal")
}
\keyword{ graphics }
rgl/man/ageSetter.Rd 0000644 0001762 0000144 00000005502 14145464133 014032 0 ustar ligges users \name{ageSetter}
\alias{ageSetter}
\title{
Obsolete function to set WebGL scene properties based on the age of components
of objects
}
\description{
Many RGL shapes contain lists of vertices with various
attributes (available via \code{\link{rgl.attrib}}). This function
modifies the data for those attributes in a WebGL scene.
}
\usage{
ageSetter(births, ages,
colors = NULL, alpha = NULL, radii = NULL,
vertices = NULL, normals = NULL, origins = NULL,
texcoords = NULL,
objids, prefixes = "", digits = 7,
param = seq(floor(min(births)), ceiling(max(births))))
}
\arguments{
\item{births}{
Numeric vector with one value per vertex, used to determine the
\dQuote{age} of the vertex when displaying it.
}
\item{ages}{
A non-decreasing sequence of \dQuote{ages}.
}
\item{colors, alpha, radii, vertices, normals, origins, texcoords}{
Attributes of the vertices. Non-\code{NULL} attributes will be
interpolated from these values. See the Details section below.
}
\item{objids, prefixes}{
The object ids and scene prefixes to modify. These are recycled to
the same length.
}
\item{digits}{
How many digits to output in the generated Javascript code.
}
\item{param}{
Default values to be used by a slider control calling the generated
function.
}
}
\details{
The vertex attributes
are specified as follows:
\describe{
\item{colors}{A vector of colors in a format suitable for input to \code{\link{col2rgb}}}
\item{alpha}{A numeric vector of alpha values between 0 and 1.}
\item{radii}{A numeric vector of sphere radii.}
\item{vertices}{A 3-column matrix of vertex coordinates.}
\item{normals}{A 3-column matrix of vertex normals.}
\item{origins}{A 2-column matrix of origins for text or sprites.}
\item{texcoords}{A 2-column matrix of texture coordinates.}
}
All attributes must have the same number of entries (rows for the matrices)
as the \code{ages} vector. The \code{births} vector must have the
same number of entries as the number of vertices in the object.
Not all objects contain all attributes listed here; if one is
chosen that is not a property of the corresponding object, a
Javascript \code{alert()} will be generated.
}
\value{
A character vector of class \code{c("ageSetter", "propertySetter")}
containing Javascript
code defining a function suitable for use in a \code{\link{propertySlider}}.
The function takes a single argument, \code{time}, and uses it to compute the
\dQuote{age} of vertex \code{i} as \code{time - births[i]}.
Those are then used with the \code{ages}
argument to linearly interpolate settings of the specified attributes.
Extrapolation is constant. Repeated values in \code{ages} can be used
to obtain discontinuities in the settings.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{propertySlider}}; more detailed control is available in
\code{\link{vertexSetter}}.
}
rgl/man/identify3d.Rd 0000644 0001762 0000144 00000003174 14100762640 014147 0 ustar ligges users \name{identify3d}
\alias{identify3d}
\title{
Identify points in plot
}
\description{
Identify points in a plot, similarly to the \code{\link{identify}} function
in base graphics.
}
\usage{
identify3d(x, y = NULL, z = NULL, labels = seq_along(x), n = length(x),
plot = TRUE, adj = c(-0.1, 0.5), tolerance = 20,
buttons = c("right", "middle"))
}
\arguments{
\item{x, y, z}{coordinates of points in a scatter plot. Alternatively, any
object which defines coordinates (see \code{\link{xyz.coords}})
can be given as \code{x}, and \code{y} and \code{z} left missing.}
\item{labels}{an optional character vector giving labels for the
points. Will be coerced using \code{\link{as.character}}, and
recycled if necessary to the length of \code{x}.}
\item{n}{the maximum number of points to be identified.}
\item{plot}{logical: if \code{plot} is \code{TRUE}, the labels are
printed near the points and if \code{FALSE} they are omitted.}
\item{adj}{numeric vector to use as \code{adj} parameter to
\code{\link{text3d}} when plotting the labels.}
\item{tolerance}{the maximal distance (in pixels)
for the pointer to be \sQuote{close enough} to a point.}
\item{buttons}{a length 1 or 2 character vector giving the buttons
to use for selection and quitting.}
}
\details{
If \code{buttons} is length 1, the user can quit by reaching \code{n}
selections, or by hitting the
escape key, but the result will be lost if escape is used.
}
\value{
A vector of selected indices.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{identify}} for base graphics, \code{\link{select3d}} for selecting regions.
}
\keyword{ graphics }
rgl/man/abclines.Rd 0000644 0001762 0000144 00000002243 14100762640 013661 0 ustar ligges users \name{abclines3d}
\alias{abclines3d}
\title{
Lines intersecting the bounding box
}
\description{
This adds mathematical lines to a scene. Their intersection with the current
bounding box will be drawn.
}
\usage{
abclines3d(x, y = NULL, z = NULL, a, b = NULL, c = NULL, ...)
}
\arguments{
\item{x, y, z}{
Coordinates of points through which each line passes.
}
\item{a, b, c}{
Coordinates of the direction vectors for the lines.
}
\item{...}{
Material properties.
}
}
\details{
Draws the segment of a line that intersects the current
bounding box of the scene using the parametrization
\eqn{ (x, y, z) + (a, b, c) * s } where \eqn{s} is a real number.
Any reasonable way of defining the
coordinates \code{x, y, z} and \code{a, b, c} is acceptable.
See the function \code{\link[grDevices]{xyz.coords}}
for details.
}
\value{
A shape ID of the object is returned invisibly.
}
\seealso{
\code{\link{planes3d}}, \code{\link{rgl.planes}} for mathematical planes.
\code{\link{segments3d}} draws sections of lines that
do not adapt to the bounding box.
}
\examples{
plot3d(rnorm(100), rnorm(100), rnorm(100))
abclines3d(0, 0, 0, a = diag(3), col = "gray")
}
\keyword{ dynamic }
rgl/man/triangulate.Rd 0000644 0001762 0000144 00000005556 14100762641 014433 0 ustar ligges users \name{triangulate}
\alias{triangulate}
\title{
Triangulate a two-dimensional polygon
}
\description{
This algorithm decomposes a general polygon into simple
polygons and uses the \dQuote{ear-clipping} algorithm to triangulate it.
Polygons with holes are supported.
}
\usage{
triangulate(x, y = NULL, z = NULL, random = TRUE, plot = FALSE, partial = NA)
}
\arguments{
\item{x, y, z}{
Coordinates of a two-dimensional polygon in a format supported by \code{\link{xyz.coords}}.
See Details for how \code{z} is handled.
}
\item{random}{
Whether to use a random or deterministic triangulation.
}
\item{plot}{
Whether to plot the triangulation; mainly for debugging purposes.
}
\item{partial}{
If the triangulation fails, should partial results be returned?
}
}
\details{
Normally \code{triangulate} looks only at the \code{x} and \code{y}
coordinates. However, if one of those is constant, it is replaced
with the \code{z} coordinate if present.
The algorithm works as follows. First, it breaks the polygon into
pieces separated by \code{NA} values in \code{x} or \code{y}.
Each of these pieces should be a simple, non-self-intersecting
polygon, separate from the other pieces.
(Though some minor exceptions to this rule may work, none
are guaranteed). The nesting of these pieces is determined.
The \dQuote{outer} polygon(s) are then merged with the
polygons that they immediately contain, and each of these
pieces is triangulated using the ear-clipping algorithm.
Finally, all the triangulated pieces are put together into one
result.
}
\value{
A three-by-n array giving the indices of the vertices of
each triangle. (No vertices are added; only the original
vertices are used in the triangulation.)
The array has an integer vector attribute \code{"nextvert"}
with one entry per vertex, giving the index of the next
vertex to proceed counter-clockwise around outer
polygon boundaries, clockwise around inner boundaries.
}
\references{
See the Wikipedia article \dQuote{polygon triangulation}
for a description of the ear-clipping algorithm.
}
\author{
Duncan Murdoch
}
\note{
Not all inputs will succeed, even when a triangulation is
possible. Generally using \code{random = TRUE} will find
a successful triangulation if one exists, but it may
occasionally take more than one try.
}
\seealso{
\code{\link{extrude3d}} for a solid extrusion of a polygon, \code{\link{polygon3d}} for
a flat display; both use \code{triangulate}.
}
\examples{
theta <- seq(0, 2*pi, len = 25)[-25]
theta <- c(theta, NA, theta, NA, theta, NA, theta, NA, theta)
r <- c(rep(1.5, 24), NA, rep(0.5, 24), NA, rep(0.5, 24), NA, rep(0.3, 24), NA, rep(0.1, 24))
dx <- c(rep(0, 24), NA, rep(0.6, 24), NA, rep(-0.6, 24), NA, rep(-0.6, 24), NA, rep(-0.6, 24))
x <- r*cos(theta) + dx
y <- r*sin(theta)
plot(x, y, type = "n")
polygon(x, y)
triangulate(x, y, plot = TRUE)
open3d()
polygon3d(x, y, x - y, col = "red")
}
\keyword{ graphics }
rgl/man/selectpoints3d.Rd 0000644 0001762 0000144 00000005701 14100762641 015047 0 ustar ligges users \name{selectpoints3d}
\alias{selectpoints3d}
\title{
Select points from a scene
}
\description{
This function uses the \code{\link{select3d}} function to allow the user to choose a
point or region in the scene, then reports on all the vertices in or near that selection.
}
\usage{
selectpoints3d(objects = ids3d()$id, value = TRUE, closest = TRUE, % $
multiple = FALSE, ...)
}
\arguments{
\item{objects}{
A vector of object id values to use for the search.
}
\item{value}{
If \code{TRUE}, return the coordinates of the points; otherwise, return
their indices.
}
\item{closest}{
If \code{TRUE}, return the points closest to the selection of no points are
exactly within it.
}
\item{multiple}{
If \code{TRUE} or a function, do multiple selections. See the Details below.
}
\item{\dots}{
Other parameters to pass to \code{\link{select3d}}.
}
}
\details{
The \code{multiple} argument may be a logical value or a function. If logical,
it controls whether multiple selections will be performed. If
\code{multiple} is \code{FALSE}, a single selection will be performed;
it might contain multiple points. If \code{TRUE}, multiple selections
will occur and the results will be combined into a single matrix.
If \code{multiple} is a function, it should take a single argument.
This function will be called with the argument set to a matrix
containing newly added rows to the value, i.e.
it will contain coordinates of the newly selected points (if
\code{value = TRUE}), or the indices of the points (if \code{value =
FALSE}). It should return a logical value, \code{TRUE} to indicate
that selection should continue, \code{FALSE} to indicate that it
should stop.
In either case, if multiple selections are being performed, the \code{ESC} key will
stop the process.
}
\value{
If \code{value} is \code{TRUE}, a 3-column matrix giving the coordinates of the
selected points. All rows in the matrix will be unique even if multiple vertices
have the same coordinates.
If \code{value} is \code{FALSE}, a 2-column matrix containing columns:
\item{id}{The object id containing the point.}
\item{index}{The index of the point within \code{\link{rgl.attrib}(id, "vertices")}.
If multiple points have the same coordinates, all indices will be returned.}
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{select3d}} to return a selection function.
}
\examples{
xyz <- cbind(rnorm(20), rnorm(20), rnorm(20))
ids <- plot3d( xyz )
if (interactive()) {
# Click near a point to select it and put a sphere there.
# Press ESC to quit...
# This version returns coordinates
selectpoints3d(ids["data"],
multiple = function(x) {
spheres3d(x, color = "red", alpha = 0.3, radius = 0.2)
TRUE
})
# This one returns indices
selectpoints3d(ids["data"], value = FALSE,
multiple = function(ids) {
spheres3d(xyz[ids[, "index"], , drop = FALSE], color = "blue",
alpha = 0.3, radius = 0.2)
TRUE
})
}
}
\keyword{ graphics }
rgl/man/scene.Rd 0000644 0001762 0000144 00000005462 14146446052 013212 0 ustar ligges users \name{scene}
\alias{clear3d}
\alias{pop3d}
\alias{ids3d}
\title{Scene management}
\description{
Clear shapes, lights, bbox
}
\usage{
clear3d( type = c("shapes", "bboxdeco", "material"), defaults, subscene = 0 )
pop3d( type = "shapes", id = 0, tag = NULL)
ids3d( type = "shapes", subscene = NA, tags = FALSE )
}
\arguments{
\item{type}{Select subtype(s):
\describe{
\item{"shapes"}{shape stack}
\item{"lights"}{light stack}
\item{"bboxdeco"}{bounding box}
\item{"userviewpoint"}{user viewpoint}
\item{"modelviewpoint"}{model viewpoint}
\item{"material"}{material properties}
\item{"background"}{scene background}
\item{"subscene"}{subscene list}
\item{"all"}{all of the above}
}
}
\item{defaults}{default values to use after clearing}
\item{subscene}{which subscene to work with. \code{NA} means the current one,
\code{0} means the whole scene}
\item{id}{vector of ID numbers of items to remove}
\item{tag}{override \code{id} with objects matching
these \code{tag} material properties}
\item{tags}{logical; whether to return \code{tag} column.}
}
\details{
RGL holds several lists of objects in each scene.
There are lists for shapes, lights, bounding box decorations, subscenes, etc.
\code{clear3d} clears the specified stack, or restores
the defaults for the bounding box (not visible) or viewpoint.
With \code{id = 0} \code{pop3d} removes
the last added node on the list (except for subscenes: there it
removes the active subscene). The \code{id} argument
may be used to specify arbitrary item(s) to remove; if \code{id != 0},
the \code{type} argument is ignored.
\code{clear3d} may also be used to clear material properties
back to their defaults.
\code{clear3d} has an optional \code{defaults} argument, which defaults to
\code{\link{r3dDefaults}}. Only the \code{materials} component of this argument
is currently used by \code{clear3d}.
\code{ids3d} returns a dataframe containing the IDs in the currently active subscene
by default, or a specified subscene, or if \code{subscene = 0}, in the whole
rgl window along with an indicator of their type and if \code{tags = TRUE}, the
\code{tag} value for each.
Note that clearing the light stack leaves the scene in darkness; it should normally
be followed by a call to \code{\link{light3d}} or \code{\link{light3d}}.
}
\seealso{
\code{\link{rgl}},
\code{\link{bbox3d}},
\code{\link{light3d}},
\code{\link{open3d}} to open a new window.
}
\examples{
x <- rnorm(100)
y <- rnorm(100)
z <- rnorm(100)
p <- plot3d(x, y, z, type = 's', tag = "plot")
ids3d()
lines3d(x, y, z)
ids3d(tags = TRUE)
if (interactive() && !rgl.useNULL()) {
readline("Hit enter to change spheres")
pop3d(id = p["data"])
spheres3d(x, y, z, col = "red", radius = 1/5)
box3d()
}
}
\keyword{dynamic}
rgl/man/turn3d.Rd 0000644 0001762 0000144 00000001531 14145464133 013324 0 ustar ligges users \name{turn3d}
\alias{turn3d}
\title{
Create a solid of rotation from a two-dimensional curve
}
\description{
This function \dQuote{turns} the curve (as on a lathe) to form a
solid of rotation along the x axis.
}
\usage{
turn3d(x, y = NULL, n = 12, smooth = FALSE, ...)
}
\arguments{
\item{x, y}{
Points on the curve, in a form suitable for \code{\link{xy.coords}}.
The \code{y} values must be non-negative.
}
\item{n}{
How many steps in the rotation?
}
\item{smooth}{
logical; whether to add normals for a smooth appearance.
}
\item{...}{
Additional parameters to pass to \code{\link{tmesh3d}}.
}
}
\value{
A mesh object containing triangles and/or quadrilaterals.
}
\author{
Fang He and Duncan Murdoch
}
\seealso{
\code{\link{extrude3d}}
}
\examples{
x <- 1:10
y <- rnorm(10)^2
open3d()
shade3d(turn3d(x, y), col = "green")
}
\keyword{ graphics }
rgl/man/shapelist3d.Rd 0000644 0001762 0000144 00000003456 14100762641 014334 0 ustar ligges users \name{shapelist3d}
\alias{shapelist3d}
\title{ Create and plot a list of shapes }
\description{
These functions create and plot a list of shapes.
}
\usage{
shapelist3d(shapes, x = 0, y = NULL, z = NULL, size = 1, matrix = NULL, override = TRUE,
..., plot = TRUE)
}
\arguments{
\item{shapes}{ A single \code{shape3d} object, or a list of them. }
\item{x, y, z}{ Translation(s) to apply }
\item{size}{ Scaling(s) to apply }
\item{matrix}{ A single matrix transformation, or a list of them. }
\item{override}{ Whether the material properties should override the ones in the shapes. }
\item{\dots}{ Material properties to apply. }
\item{plot}{ Whether to plot the result. }
}
\details{
\code{shapelist3d} is a quick way to create a complex object made up of simpler ones.
Each of the arguments \code{shapes} through \code{override} may be a vector of
values (a list in the case of \code{shapes} or \code{matrix}). All values
will be recycled to produce a list of shapes as long as the longest of them.
The \code{\link{xyz.coords}} function will be used to process the \code{x},
\code{y} and \code{z} arguments, so a matrix may be used as \code{x} to
specify all three. If a vector is used for \code{x} but \code{y} or \code{z}
is missing, default values of \code{0} will be used.
The \code{"shapelist3d"} class is simply a list of \code{"shape3d"} objects.
Methods for \code{\link{dot3d}}, \code{\link{wire3d}}, \code{\link{shade3d}},
\code{\link{translate3d}}, \code{\link{scale3d}}, and \code{\link{rotate3d}}
are defined for these objects.
}
\value{
An object of class \code{c("shapelist3d", "shape3d")}.
}
\author{ Duncan Murdoch }
\seealso{ \code{\link{mesh3d}} }
\examples{
shapelist3d(icosahedron3d(), x = rnorm(10), y = rnorm(10), z = rnorm(10), col = 1:5, size = 0.3)
}
\keyword{ dynamic }
rgl/man/plotmath3d.Rd 0000644 0001762 0000144 00000004357 14142256754 014202 0 ustar ligges users \name{plotmath3d}
\alias{plotmath3d}
\title{
Draw text using base graphics math plotting
}
\description{
To plot mathematical text, this function uses base graphics
functions to plot it to a \file{.png} file, then uses that
file as a texture in a sprite.
}
\usage{
plotmath3d(x, y = NULL, z = NULL, text, cex = par("cex"),
adj = 0.5, pos = NULL, offset = 0.5,
fixedSize = TRUE, startsize = 480, initCex = 5, ...)
}
\arguments{
\item{x, y, z}{coordinates. Any reasonable way of defining the
coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}}
for details.}
\item{text}{
A character vector or expression. See
\code{\link[grDevices]{plotmath}} for how expressions are
interpreted.
}
\item{cex}{
Character size expansion.
}
\item{adj}{ one value specifying the horizontal adjustment, or two,
specifying horizontal and vertical adjustment respectively, or three, for depth as well. }
\item{pos, offset}{ alternate way to specify \code{adj}; see \code{\link{text3d}}}
\item{fixedSize}{
Should the resulting sprite behave like the default
ones, and resize with the scene, or like text, and
stay at a fixed size?
}
\item{startsize, initCex}{
These parameters are unlikely to be needed by users.
\code{startsize} is an over-estimate of the size (in pixels) of the
largest expression. Increase this if large expressions
are cut off. \code{initCex} is the size of text used
to form the bitmap. Increase this if letters look too blurry
at the desired size.
}
\item{\dots}{
Additional arguments to pass to
\code{\link[graphics]{text}} when drawing the text.
}
}
\note{
The \code{\link{text3d}} function passes calls to this
function if its \code{usePlotmath} argument is \code{TRUE}.
The default value is determined by examining its
\code{texts} argument; if it looks like an expression,
\code{plotmath3d} is used.
}
\value{
Called for the side effect of displaying the sprites.
The shape ID of the displayed object is returned.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{text3d}}
}
\examples{
open3d()
plotmath3d(1:3, 1:3, 1:3, expression(x[1] == 1, x[2] == 2, x[3] == 3))
# This lets the text resize with the plot
text3d(4, 4, 4, "resizeable text", usePlotmath = TRUE, fixedSize = FALSE)
} rgl/man/rgl.select.Rd 0000644 0001762 0000144 00000001440 14100762641 014142 0 ustar ligges users \name{rgl.select}
\alias{rgl.select}
\title{
Switch to select mode, and return the mouse position selected
}
\description{
Mostly for internal use, this function temporarily
installs a handler on a button of the mouse that will
return the mouse coordinates of one click and drag rectangle.
}
\usage{
rgl.select(button = c("left", "middle", "right"),
dev = cur3d(), subscene = currentSubscene3d(dev))
}
\arguments{
\item{button}{
Which button to use?
}
\item{dev, subscene}{
The RGL device and subscene to work with
}
}
\value{
A vector of four coordinates: the X and Y coordinates of the start and end of the
dragged rectangle.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{rgl.select3d}}, a version that allows the selection region to be used to
select points in the scene.
}
rgl/man/bg.Rd 0000644 0001762 0000144 00000006651 14100762640 012500 0 ustar ligges users \name{bg3d}
\alias{rgl.bg}
\alias{bg3d}
\title{Set up background}
\description{
Set up the background of the scene.
}
\usage{
bg3d(...)
rgl.bg( sphere = FALSE, fogtype = "none", color = c("black", "white"),
back = "lines", fogScale = 1, ...)
}
\arguments{
\item{fogtype}{fog type:
\describe{
\item{"none"}{no fog}
\item{"linear"}{linear fog function}
\item{"exp"}{exponential fog function}
\item{"exp2"}{squared exponential fog function}
}
Fog only applies to objects with \code{\link{material3d}}
property \code{fog} set to \code{TRUE}.
}
\item{sphere}{
logical, if true, an environmental sphere geometry is used for the background decoration.
}
\item{color}{
Primary color is used for background clearing and as fog color.
Secondary color is used for background sphere geometry. See \code{\link{material3d}} for details.
}
\item{back}{
Specifies the fill style of the sphere geometry. See \code{\link{material3d}} for details.
}
\item{fogScale}{
Scaling for fog. See Details.
}
\item{ ... }{Material properties. See \code{\link{material3d}} for details.}
}
\details{
If sphere is set to \code{TRUE}, an environmental sphere enclosing the whole scene is drawn.
If not, but the material properties include a bitmap as a texture, the bitmap is drawn in the
background of the scene. (The bitmap colors modify the general color setting.)
If neither a sphere nor a bitmap background is drawn, the background is filled with a
solid color.
The \code{fogScale} parameter should be a positive value
to change the density of the fog in the plot. For
\code{fogtype = "linear"} it multiplies the density of the
fog; for the exponential fog types it multiplies the density
parameter used in the display.
See
\href{https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glFog.xml}{the OpenGL 2.1 reference}
for the formulas used in the fog calculations within \R (though the
\code{"exp2"} formula appears to be wrong, at least on my
system). In WebGL displays,
the following rules are used. They appear to match the
rules used in \R on my system.
\itemize{
\item{For \code{"linear"} fog, the near clipping plane is
taken as \eqn{c=0}, and the
far clipping plane is taken as \eqn{c=1}. The
amount of fog is \eqn{s * c} clamped to a 0 to 1
range, where \eqn{s = fogScale}.}
\item{For \code{"exp"} and \code{"exp2"} fog, the observer location
is negative at a distance depending on the field of view.
The formula for the distance is
\deqn{c = [1-sin(theta)]/[1 + sin(theta)]}
where \eqn{theta = FOV/2}.
We calculate \deqn{c' = d(1-c) + c}
so \eqn{c'} runs from 0 at the observer to
1 at the far clipping plane.}
\item{For \code{"exp"} fog, the amount of fog is
\eqn{1 - exp(-s * c')}.}
\item{For \code{"exp2"} fog, the amount of fog is
\eqn{1 - exp[-(s * c')^2]}.}
}
}
\examples{
open3d()
# a simple white background
bg3d("white")
# the holo-globe (inspired by star trek):
bg3d(sphere = TRUE, color = c("black", "green"), lit = FALSE, back = "lines" )
# an environmental sphere with a nice texture.
bg3d(sphere = TRUE, texture = system.file("textures/sunsleep.png", package = "rgl"),
back = "filled" )
# The same texture as a fixed background
open3d()
bg3d(texture = system.file("textures/sunsleep.png", package = "rgl"), col = "white")
}
\seealso{
\code{\link{material3d}}, \code{\link{bgplot3d}} to add a 2D plot as background.
}
\keyword{dynamic}
rgl/man/check3d.Rd 0000644 0001762 0000144 00000000703 14100762640 013404 0 ustar ligges users \name{.check3d}
\alias{.check3d}
\alias{check3d}
\title{
Check for an open RGL window.
}
\description{
Mostly for internal use, this function returns the current device
number if one exists, or opens a new device and returns that.
}
\usage{
.check3d()
}
\value{
The device number of an RGL device.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{open3d}}
}
\examples{
rgl.dev.list()
.check3d()
rgl.dev.list()
.check3d()
rgl.dev.list()
rgl.close()
}
rgl/man/primitive.Rd 0000644 0001762 0000144 00000006454 14145464133 014126 0 ustar ligges users \name{rgl.primitive}
\alias{rgl.primitive}
\alias{rgl.points}
\alias{rgl.lines}
\alias{rgl.linestrips}
\alias{rgl.triangles}
\alias{rgl.quads}
\title{Add primitive set shape}
\description{
Adds a shape node to the current scene. These low-level
functions should not normally be called by users.
}
\usage{
rgl.points(x, y = NULL, z = NULL, ... )
rgl.lines(x, y = NULL, z = NULL, ... )
rgl.linestrips(x, y = NULL, z = NULL, ...)
rgl.triangles(x, y = NULL, z = NULL, normals = NULL, texcoords = NULL, ... )
rgl.quads(x, y = NULL, z = NULL, normals = NULL, texcoords = NULL, ... )
}
\arguments{
\item{x, y, z}{coordinates. Any reasonable way of defining the
coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}}
for details.}
\item{normals}{Normals at each point.}
\item{texcoords}{Texture coordinates at each point.}
\item{ ... }{Material properties (see \code{\link{rgl.material}} for details) or \code{indices} (see the note below).}
}
\details{
Adds a shape node to the scene. The appearance is defined by the material properties.
See \code{\link{rgl.material}} for details.
The names of these functions correspond to OpenGL primitives. They
all take a sequence of vertices in \code{x, y, z}. The only non-obvious
ones are \code{rgl.lines} which draws line segments based on
pairs of vertices, and \code{rgl.linestrips} which joins the
vertices.
For triangles and quads, the normals at each vertex may be specified
using \code{normals}. These may be given in any way that would be
acceptable as a single argument to \code{\link[grDevices]{xyz.coords}}.
These need not match the actual normals to the polygon:
curved surfaces can be simulated by using other choices of normals.
Texture coordinates may also be specified. These may be given in
any way that would be acceptable as a single argument to
\code{\link[grDevices]{xy.coords}}, and are interpreted in terms
of the bitmap specified as the material texture, with \code{(0, 0)}
at the lower left, \code{(1, 1)} at the upper right. The texture
is used to modulate the color of the polygon.
These are the lower level functions called by
\code{\link{points3d}}, \code{\link{segments3d}},
\code{\link{lines3d}}, etc. The two principal differences between
the \code{rgl.*} functions and the \code{*3d} functions are that the
former set all unspecified material properties to defaults, whereas
the latter use current values as defaults; the former make
persistent changes to material properties with each call, whereas
the latter make temporary changes only for the duration of the call.
}
\note{
All of these functions support an argument called
\code{indices}, which allows vertices (and other attributes)
to be re-used, as they are in objects created by \code{\link{mesh3d}} and related functions. This is
intended to be used on smooth surfaces, where each shared
vertex has just one value for normals, colors and texture
coordinates.
For shapes with flat-looking faces (e.g. polyhedra like \code{\link{cube3d}}),
the vertices \bold{must} be duplicated
to be rendered properly.
}
\value{
Each primitive function returns the integer object ID of the shape that
was added to the scene. These can be passed to \code{\link{pop3d}}
to remove the object from the scene.
}
\keyword{internal}
rgl/man/sceneChange.Rd 0000644 0001762 0000144 00000004702 14100762641 014307 0 ustar ligges users \name{sceneChange}
\alias{sceneChange}
\alias{registerSceneChange}
\title{
Make large change to a scene from Shiny
}
\description{
These functions allow Shiny apps to make relatively large changes
to a scene, adding and removing objects from it.
}
\usage{
sceneChange(elementId, x = scene3d(minimal),
delete = NULL, add = NULL, replace = NULL,
material = FALSE, rootSubscene = FALSE,
delfromSubscenes = NULL, skipRedraw = FALSE,
minimal = TRUE)
registerSceneChange()
}
\arguments{
\item{elementId}{
The id of the element holding the \code{rglClass} instance.
}
\item{x}{
The new scene to use as a source for objects to add.
}
\item{delete, add, replace}{
Object ids to modify in the scene. The \code{delete} and
\code{replace} ids must be present in the old scene in the browser;
the \code{add} and \code{replace} ids must be present in \code{x}.
}
\item{material}{
Logical to indicate whether default material should be updated.
}
\item{rootSubscene}{
Logical to indicate whether root subscene should be updated.
}
\item{delfromSubscenes}{
A vector of subscene ids that may have been changed by
deletions. By default, all subscenes in \code{x} are used,
but the objects may be included in subscenes in the browser
that are different.
}
\item{skipRedraw}{
If \code{TRUE}, stop the scene from redrawing until \code{skipRedraw=FALSE} is sent. If \code{NA}, don't redraw this time, but don't
change the state of the \code{skipRedraw} flag.
}
\item{minimal}{
See \code{\link{scene3d}}.
}
}
\details{
\code{registerSceneChange} must be called in the UI component
of a Shiny app to register the \code{"sceneChange"} custom
message.
}
\value{
\code{registerSceneChange} returns the HTML code to register the
message.
\code{sceneChange} returns a list to be used as the \code{"sceneChange"}
message to change the scene. Use
\code{\link[shiny:session]{shiny::session$sendCustomMessage}} to send it.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{playwidget}} for a different approach to modifying
scenes that can be much faster, but may be less flexible. The
Shiny demo in this package makes use of all of these approaches.
}
\examples{
\dontrun{
shinyUI(fluidPage(
registerSceneChange(),
actionButton("thebutton", "Change")
))
shinyServer(function(input, output, session) {
observeEvent(input$thebutton, {
session$sendCustomMessage("sceneChange",
sceneChange("thewidget", delete = deletes, add = adds))
})
})
}
}
rgl/man/observer3d.Rd 0000644 0001762 0000144 00000003120 14100762640 014152 0 ustar ligges users \name{observer3d}
\alias{observer3d}
\title{
Set the observer location
}
\description{
This function sets the location of the viewer.
}
\usage{
observer3d(x, y = NULL, z = NULL, auto = FALSE)
}
\arguments{
\item{x, y, z}{
The location as a 3 vector, using the usual \code{xyz.coords}
conventions for specification. If \code{x} is missing
or any coordinate is \code{NA}, no change will be made to the
location.
}
\item{auto}{
If \code{TRUE}, the location will be set
automatically by RGL to make the whole bounding box visible.
}
}
\details{
This function
sets the location of the viewer relative to the scene, after the model transformations
(scaling, rotation) have been done, but before lighting or projection have been
applied. (See \code{\link{par3d}} for details on the rendering pipeline.)
The coordinate system is a slightly strange one: the X coordinate
moves the observer location from left to right, and the Y coordinate moves up
and down. The Z coordinate changes the depth from the viewer. All are measured
relative to the center of the bounding box (\code{par("bbox")}) of the subscene.
The observer always looks in the positive Z direction
after the model rotation have been done. The coordinates are in post-scaling
units.
}
\note{
This function is likely to change in future versions of RGL, to allow more
flexibility in the specification of the observer's location and orientation.
}
\value{
Invisibly returns the previous value.
}
\author{
Duncan Murdoch
}
\examples{
example(surface3d) # The volcano data
observer3d(0, 0, 440) # Viewed from very close up
}
\keyword{ graphics }
rgl/man/bgplot3d.Rd 0000644 0001762 0000144 00000004223 14145464133 013624 0 ustar ligges users \name{bgplot3d}
\alias{bgplot3d}
\alias{legend3d}
\title{Use base graphics for RGL background}
\description{
Add a 2D plot or a legend in the background of an RGL window.
}
\usage{
bgplot3d(expression, bg.color = getr3dDefaults("bg", "color"),
magnify = 1, ...)
legend3d(...)
}
\arguments{
\item{expression}{
Any plotting commands to produce a plot.
}
\item{bg.color}{
The color to use for the background.
}
\item{magnify}{
Multiplicative factor to apply to size of window when producing background
plot.
}
\item{...}{
For \code{legend3d}, arguments to pass to \code{bgplot3d}
or \code{\link{legend}}; for \code{bgplot3d},
arguments to pass to \code{\link{bg3d}}.
}
}
\details{
The \code{bgplot3d} function opens a \code{\link{png}} device and executes \code{expression},
producing a plot there. This plot is then used as a bitmap background for the current
RGL subscene.
The \code{legend3d} function draws a standard 2D legend to the background of the current
subscene by calling \code{bgplot3d} to open a device, and setting up a plot region there
to fill the whole display.
}
\value{
The \code{bgplot3d} function invisibly returns the ID of the background object that was created,
with attribute \code{"value"} holding the value returned when the \code{expression} was
evaluated.
The \code{legend3d} function does similarly. The \code{"value"} attribute is the result
of the call to \code{\link{legend}}. The scaling of the coordinates runs from 0 to 1
in X and Y.
}
\author{
Duncan Murdoch
}
\note{
Because the background plots are drawn as bitmaps, they do not resize very gracefully.
It's best to size your window first, then draw the background at that size.
}
\seealso{
\code{\link{bg3d}} for other background options.
}
\examples{
x <- rnorm(100)
y <- rnorm(100)
z <- rnorm(100)
open3d()
# Needs to be a bigger window than the default
par3d(windowRect = c(100, 100, 612, 612))
parent <- currentSubscene3d()
mfrow3d(2, 2)
plot3d(x, y, z)
next3d(reuse = FALSE)
bgplot3d(plot(y, z))
next3d(reuse = FALSE)
bgplot3d(plot(x, z))
next3d(reuse = FALSE)
legend3d("center", c("2D Points", "3D Points"), pch = c(1, 16))
useSubscene3d(parent)
}
\keyword{ graphics }
rgl/man/par3dinterp.Rd 0000644 0001762 0000144 00000006050 14100762640 014334 0 ustar ligges users \name{par3dinterp}
\alias{par3dinterp}
\title{Interpolator for par3d parameters}
\description{
Returns a function which interpolates \code{par3d} parameter values,
suitable for use in animations.
}
\usage{
par3dinterp(times = NULL, userMatrix, scale, zoom, FOV,
method = c("spline", "linear"),
extrapolate = c("oscillate", "cycle", "constant", "natural"),
dev = cur3d(), subscene = par3d("listeners", dev = dev))
}
\arguments{
\item{times}{ Times at which values are recorded or a list; see below }
\item{userMatrix}{ Values of \code{par3d("userMatrix")} }
\item{scale}{ Values of \code{par3d("scale")} }
\item{zoom}{ Values of \code{par3d("zoom")} }
\item{FOV}{ Values of \code{par3d("FOV")} }
\item{method}{ Method of interpolation }
\item{extrapolate}{ How to extrapolate outside the time range }
\item{dev}{ Which RGL device to use }
\item{subscene}{ Which subscene to use }
}
\details{
This function is intended to be used in constructing animations. It produces
a function that returns a list suitable to pass to \code{\link{par3d}}, to set
the viewpoint at a given point in time.
All of the parameters are optional. Only those \code{par3d} parameters that are
specified will be returned.
The input values other than \code{times} may each be specified as
lists, giving the parameter value settings at a fixed time, or as
matrices or arrays. If not lists, the following formats should be
used: \code{userMatrix} can be a \code{4 x 4 x n} array, or a \code{4
x 4n} matrix; \code{scale} should be an \code{n x 3} matrix;
\code{zoom} and \code{FOV} should be length \code{n} vectors.
An alternative form of input is to put all of the above arguments into
a list (i.e. a list of lists, or a list of arrays/matrices/vectors),
and pass it as the first argument. This is the most convenient way to
use this function with the function
\code{\link{tkpar3dsave}}.
Interpolation is by cubic spline or linear interpolation in an appropriate
coordinate-wise fashion. Extrapolation may oscillate
(repeat the sequence forward, backward, forward, etc.), cycle (repeat
it forward), be constant (no repetition outside the specified time
range), or be natural (linear on an appropriate scale).
In the case of cycling, the first and last specified values
should be equal, or the last one will be dropped. Natural extrapolation
is only supported with spline interpolation.
}
\value{
A function is returned. The function takes one argument, and returns a list of
\code{par3d} settings interpolated to that time.
}
\note{
Prior to \pkg{rgl} version 0.95.1476, the
\code{subscene} argument defaulted to the
current subscene, and any additional entries would
be ignored by \code{\link{play3d}}. The current
default value of \code{par3d("listeners", dev = dev)} means that all subscenes that share
mouse responses will also share modifications
by this function.
}
\author{Duncan Murdoch }
\seealso{ \code{\link{play3d}} to play the animation. }
\examples{
f <- par3dinterp( zoom = c(1, 2, 3, 1) )
f(0)
f(1)
f(0.5)
\dontrun{
play3d(f)
}
}
\keyword{ dplot }
rgl/man/subdivision3d.Rd 0000644 0001762 0000144 00000004161 14100762641 014670 0 ustar ligges users \name{subdivision3d}
\alias{subdivision3d}
\alias{subdivision3d.mesh3d}
\alias{divide.mesh3d}
\alias{normalize.mesh3d}
\alias{deform.mesh3d}
\title{Subdivide a mesh}
\description{
The subdivision surface algorithm divides and refines (deforms) a
given mesh recursively to certain degree (depth).
The mesh3d algorithm consists of two stages: divide and deform.
The divide step generates for each triangle or quad four new triangles or quads, the deform
step drags the points (refinement step).
}
\usage{
subdivision3d( x, ...)
\method{subdivision3d}{mesh3d}( x, depth = 1, normalize = FALSE, deform = TRUE, ... )
divide.mesh3d(mesh, vb = mesh$vb, ib = mesh$ib, it = mesh$it )
normalize.mesh3d(mesh)
deform.mesh3d(mesh, vb = mesh$vb, ib = mesh$ib, it = mesh$it )
}
\arguments{
\item{x}{3d geometry mesh}
\item{mesh}{3d geometry mesh}
\item{depth}{recursion depth}
\item{normalize}{normalize mesh3d coordinates after division if \code{deform} is \code{TRUE}}
\item{deform}{deform mesh}
\item{it}{indices for triangular faces}
\item{ib}{indices for quad faces}
\item{vb}{matrix of vertices: 4 x n matrix (rows x, y, z, h) or equivalent
vector, where h indicates scaling of each plotted quad}
\item{...}{other arguments (unused)}
}
\details{
\code{subdivision3d} takes
a mesh object and replaces each triangle or quad with 4 new ones
by adding vertices half-way along the edges (and one in the
centre of a quad). The positions of the vertices are
deformed so that the resulting surface is smoother than the original. These operations are repeated \code{depth} times.
The other functions do the individual steps of the subdivision.
\code{divide.mesh3d} adds the extra vertices. \code{deform.mesh3d}
does the smoothing by replacing each vertex with the average of each of its neighbours. \code{normalize.mesh3d}
normalizes the homogeneous coordinates, by setting the
4th coordinate to 1. (The 4th coordinate is used as a
weight in the deform step.)
}
\examples{
open3d()
shade3d( subdivision3d( cube3d(), depth = 3 ), color = "red", alpha = 0.5 )
}
\seealso{
\code{\link{r3d}}
\code{\link{mesh3d}}
}
\keyword{dynamic}
rgl/man/rgl.fns.Rd 0000644 0001762 0000144 00000003134 14146446052 013460 0 ustar ligges users \name{rgl.fns}
\alias{rgl.abclines}
\alias{rgl.planes}
\alias{rgl.clipplanes}
\alias{rgl.sprites}
\alias{rgl.spheres}
\alias{rgl.clear}
\alias{rgl.pop}
\alias{rgl.ids}
\title{
Low level functions that should not be called by users.
}
\description{
These functions provide the implementation for various
\code{*3d} functions designed for users to call.
}
\usage{
rgl.abclines(x, y = NULL, z = NULL, a, b = NULL, c = NULL, ...)
rgl.planes(a, b = NULL, c = NULL, d = 0, ...)
rgl.clipplanes(a, b = NULL, c = NULL, d = 0)
rgl.sprites(x, y = NULL, z = NULL, radius = 1,
shapes = NULL, userMatrix, fixedSize = FALSE,
adj = 0.5, pos = NULL, offset = 0.25, ...)
rgl.spheres(x, y = NULL, z = NULL, radius, fastTransparency = TRUE, ...)
rgl.clear( type = "shapes", subscene = 0 )
rgl.pop( type = "shapes", id = 0, tag = NULL )
rgl.ids( type = "shapes", subscene = NA, tags = FALSE )
}
\arguments{
\item{x, y, z}{
Coordinates of points
}
\item{a, b, c}{
Coordinates of the direction vectors for the lines,
or normals for the planes.
}
\item{d}{Plane offset.}
\item{radius}{Size of sprites or spheres.}
\item{fastTransparency}{Sphere drawing strategy.}
\item{type, id, subscene}{Selecting objects.}
\item{adj, pos, offset}{Positioning.}
\item{tag}{Select objects with material property
\code{tag} in this vector.}
\item{tags}{Whether to return tags.}
\item{...}{
Material properties.
}
}
\details{
See the corresponding \code{*3d} function: \code{\link{abclines3d}}, \code{\link{planes3d}}, \code{\link{clipplanes3d}}, \code{\link{sprites3d}}, \code{\link{spheres3d}}.
}
\keyword{internal}
rgl/man/plot3d.lm.Rd 0000644 0001762 0000144 00000007635 14100762641 013730 0 ustar ligges users \name{plot3d.lm}
\alias{plot3d.lm}
\title{
Method for plotting simple linear fit
}
\description{
This function provides several plots of the result of
fitting a two-predictor model.
}
\usage{
\method{plot3d}{lm}(x,
which = 1,
plane.col = "gray", plane.alpha = 0.5,
sharedMouse = TRUE,
use_surface3d,
do_grid = TRUE,
grid.col = "black",
grid.alpha = 1,
grid.steps = 5,
sub.steps = 4,
vars = get_all_vars(terms(x), x$model),
clip_to_density = 0,
...)
}
\arguments{
\item{x}{
An object inheriting from class \code{"lm"} obtained by fitting
a two-predictor model.
}
\item{which}{
Which plot to show? See Details below.
}
\item{plane.col, plane.alpha}{
These parameters control
the colour and transparency of a plane or surface.
}
\item{sharedMouse}{
If multiple plots are requested, should they share
mouse controls, so that they move in sync?
}
\item{use_surface3d}{
Use the \code{\link{surface3d}} function to plot the surface
rather than \code{\link{planes3d}}. This allows curved
surfaces to be shown. The default is \code{FALSE} if the model
looks like a simple 2 parameter linear fit, otherwise \code{TRUE}.
}
\item{do_grid}{Plot a grid.}
\item{grid.col, grid.alpha, grid.steps}{
Characteristics of the grid.
}
\item{sub.steps}{If \code{use_surface3d} is \code{TRUE},
use an internal grid of \code{grid.steps*sub.steps} to draw
the surface. \code{sub.steps > 1} allows curvature within facets.
Similarly, if \code{do_grid} is \code{TRUE}, it allows
curvature within grid lines.}
\item{vars}{A dataframe containing the variables to plot
in the first three columns, with the response assumed to be in
column 1. See the Note below.}
\item{clip_to_density}{
If positive, the surface, plane or grid will be clipped to a region with sufficient data.
}
\item{\dots}{
Other parameters to pass to the default \code{\link{plot3d}} method, to control the appearance of aspects of the plot
other than the plane.
}
}
\details{
Three plots are possible, depending on the value(s) in \code{which}:
\enumerate{
\item{(default) Show the points and the fitted plane or surface.}
\item{Show the residuals and the plane at \code{z = 0}.}
\item{Show the predicted values on the fitted plane or surface.}
}
If \code{clip_to_density} is positive, then the
surface, plane or grid will be clipped to
the region where a non-parametric density estimate
(using \code{MASS::\link{kde2d}}), normalized to have a
maximum value of 1, is greater than the given value.
This will suppress parts of the plot that aren't
supported by the observed data.
}
\value{
Called for the side effect of drawing one or more plots.
Invisibly returns a high-level vector of object ids. Names of
object ids have the plot number (in drawing order) appended.
}
\note{
The default value for the \code{vars} argument will handle
simple linear models with a response and two predictors, and
some models with functions of those two predictors. For
models that fail (e.g. models using \code{\link{poly}}), you
can include the observed values as in the third example below.
If \code{clip_to_density > 0},
\enumerate{
\item{The clipping is
approximate, so it may not agree perfectly between
surfaces, planes and grids.}
\item{This option requires the suggested packages
\pkg{MASS} and \pkg{akima}, and will be ignored with
a warning if either is not installed.}
}
}
\author{
Duncan Murdoch
}
\examples{
open3d()
ids <- plot3d(lm(mpg ~ wt + qsec, data = mtcars), which = 1:3)
names(ids)
open3d()
plot3d(lm(mpg ~ wt + I(wt^2) + qsec, data = mtcars))
open3d()
# Specify vars in the order: response, pred1, pred2.
plot3d(lm(mpg ~ poly(wt, 3) + qsec, data = mtcars),
vars = mtcars[,c("mpg", "wt", "qsec")])
open3d()
# Clip parts of the plot with few (wt, qsec) points
plot3d(lm(mpg ~ poly(wt, 3) + qsec, data = mtcars),
vars = mtcars[,c("mpg", "wt", "qsec")],
clip_to_density = 0.1)
}
rgl/man/rglMouse.Rd 0000644 0001762 0000144 00000005406 14100762641 013703 0 ustar ligges users \name{rglMouse}
\alias{rglMouse}
\title{
Generate HTML code to select mouse mode
}
\description{
This generates an HTML \code{select} element to
choose among the mouse modes supported by \code{\link{rglwidget}}.
}
\usage{
rglMouse(sceneId,
choices = c("trackball", "selecting",
"xAxis", "yAxis", "zAxis",
"polar", "zoom", "fov",
"none"),
labels = choices,
button = 1,
dev = cur3d(),
subscene = currentSubscene3d(dev),
default = par3d("mouseMode", dev = dev, subscene = subscene)[button],
stayActive = FALSE,
height = 40,
...)
}
\arguments{
\item{sceneId}{
Either an \code{\link{rglwidget}} or the \code{elementId}
from one of them.
}
\item{choices}{
Which mouse modes to support?
}
\item{labels}{
How to label each mouse mode.
}
\item{button}{
Which mouse button is being controlled.
}
\item{dev}{
The RGL device used for defaults.
}
\item{subscene}{
Which subscene is being modified.
}
\item{default}{
What is the default entry to show in the control.
}
\item{stayActive}{
Whether a selection brush should stay active if the
mouse mode is changed.
}
\item{height}{
The (relative) height of the item in the output display.
}
\item{...}{
Additional arguments to pass to \code{htmltools::tags$select()}, e.g. \code{id} or \code{class}.
}
}
\details{
A result of an \code{\link{rglwidget}} call can be passed
as the \code{sceneId} argument. This allows the widget
to be \dQuote{piped} into the \code{rglMouse} call.
The widget will appear first, the selector next in
a \code{\link[htmltools:tag]{tagList}}.
If the \code{sceneId} is a character string, it should be
the \code{elementId} of a separately constructed
\code{\link{rglwidget}} result.
Finally, the \code{sceneId} can be omitted. In this case
the \code{rglMouse} result needs to be passed into an
\code{\link{rglwidget}} call as part of the
\code{controllers} argument. This will place the selector before the
widget on the resulting display.
If the mouse mode is changed while brushing the scene,
by default the brush will be removed (and so the selection
will be cleared too). If this is not desired, set
\code{stayActive = TRUE}.
}
\value{
A browsable value to put in a web page.
}
\author{
Duncan Murdoch
}
\examples{
if (interactive() || in_pkgdown_example()) {
open3d()
xyz <- matrix(rnorm(300), ncol = 3)
id <- plot3d(xyz, col = "red", type = "s")["data"]
par3d(mouseMode = "selecting")
share <- rglShared(id)
# This puts the selector below the widget.
rglwidget(shared = share, width = 300, height = 300) \%>\% rglMouse()
# This puts the selector above the widget.
rglMouse() \%>\% rglwidget(shared = share, width = 300, height = 300, controllers = .)
}
}
rgl/man/subsceneInfo.Rd 0000644 0001762 0000144 00000002740 14100762641 014527 0 ustar ligges users \name{subsceneInfo}
\alias{subsceneInfo}
\title{
Get information on subscenes
}
\description{
This function retrieves information about the tree of subscenes shown in the active
window.
}
\usage{
subsceneInfo(id = NA, embeddings, recursive = FALSE)
}
\arguments{
\item{id}{
Which subscene to report on; \code{NA} is the current subscene. Set to \code{"root"} for the root.
}
\item{embeddings}{
Optional new setting for the embeddings for this subscene.
}
\item{recursive}{
Whether to report on children recursively.
}
}
\details{
In RGL, each window contains a tree of \dQuote{subscenes}, each containing views of
a subset of the objects defined in the window.
Rendering in each subscene depends on the viewport, the projection, and the model
transformation. Each of these characteristics may be inherited from the parent
(\code{embedding[i] = "inherit"}), may modify the parent (\code{embedding[i] = "modify"}),
or may replace the parent (\code{embedding[i] == "replace"}). All three must be
specified if \code{embeddings} is used.
}
\value{
\item{id}{The object id of the subscene}
\item{parent}{The object id of the parent subscene, if any}
\item{children}{If \code{recursive}, a list of the information for the children,
otherwise just their object ids.}
\item{embedding}{A vector of 3 components describing how this subscene is
embedded in its parent.
}
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{newSubscene3d}}
}
\examples{
example(plot3d)
subsceneInfo()
}
\keyword{ graphics }
rgl/man/material.Rd 0000644 0001762 0000144 00000022144 14145464133 013706 0 ustar ligges users \name{rgl.material}
\alias{rgl.material}
\alias{material3d}
\title{Set material properties}
\description{
Set material properties for geometry appearance.
}
\usage{
rgl.material(
color = "white",
alpha = 1.0,
lit = TRUE,
ambient = "black",
specular = "white",
emission = "black",
shininess = 50.0,
smooth = TRUE,
texture = NULL,
textype = "rgb",
texmipmap = FALSE,
texminfilter = "linear",
texmagfilter = "linear",
texenvmap = FALSE,
front = "fill",
back = "fill",
size = 3.0,
lwd = 1.0,
fog = TRUE,
point_antialias = FALSE,
line_antialias = FALSE,
depth_mask = TRUE,
depth_test = "less",
polygon_offset = c(0.0, 0.0),
margin = "",
floating = FALSE,
tag = "",
...
)
material3d(...)
}
\arguments{
\item{color}{
vector of R color characters. Represents the diffuse component in case of lighting calculation (lit = TRUE),
otherwise it describes the solid color characteristics.
}
\item{lit}{
logical, specifying if lighting calculation should take place on geometry
}
\item{ambient, specular, emission, shininess}{
properties for lighting calculation. ambient, specular, emission are R color character string values; shininess represents a
numerical.
}
\item{alpha}{
vector of alpha values between 0.0 (fully transparent) .. 1.0 (opaque).
}
\item{smooth}{
logical, specifying whether Gouraud shading (smooth) or flat shading should be used.
}
\item{texture}{
path to a texture image file. Supported formats: png.
}
\item{textype}{
specifies what is defined with the pixmap
\describe{
\item{"alpha"}{alpha values}
\item{"luminance"}{luminance}
\item{"luminance.alpha"}{luminance and alpha}
\item{"rgb"}{color}
\item{"rgba"}{color and alpha texture}
}
}
\item{texmipmap}{
Logical, specifies if the texture should be mipmapped.
}
\item{texmagfilter}{
specifies the magnification filtering type (sorted by ascending quality):
\describe{
\item{"nearest"}{texel nearest to the center of the pixel}
\item{"linear"}{weighted linear average of a 2x2 array of texels}
}
}
\item{texminfilter}{
specifies the minification filtering type (sorted by ascending quality):
\describe{
\item{"nearest"}{texel nearest to the center of the pixel}
\item{"linear"}{weighted linear average of a 2x2 array of texels}
\item{"nearest.mipmap.nearest"}{low quality mipmapping}
\item{"nearest.mipmap.linear"}{medium quality mipmapping}
\item{"linear.mipmap.nearest"}{medium quality mipmapping}
\item{"linear.mipmap.linear"}{high quality mipmapping}
}
}
\item{texenvmap}{
logical, specifies if auto-generated texture coordinates for environment-mapping
should be performed on geometry.
}
\item{front, back}{
Determines the polygon mode for the specified side:
\describe{
\item{"filled"}{filled polygon}
\item{"lines"}{wireframed polygon}
\item{"points"}{point polygon}
\item{"culled"}{culled (hidden) polygon}
}
}
\item{size}{
numeric, specifying the size of points in pixels
}
\item{lwd}{
numeric, specifying the line width in pixels
}
\item{fog}{logical, specifying if fog effect should be applied on the corresponding shape. Fog type is set in \code{\link{bg3d}}.}
\item{point_antialias, line_antialias}{logical, specifying if points should be round and lines
should be antialiased, but see Note below.}
\item{depth_mask}{logical, specifying whether the object's depth
should be stored.}
\item{depth_test}{Determines which depth test is used to see if this
object is visible, depending on its apparent depth in the scene
compared to the stored depth. Possible values are \code{"never"},
\code{"less"} (the default), \code{"equal"}, \code{"lequal"}
(less than or equal), \code{"greater"}, \code{"notequal"},
\code{"gequal"} (greater than or equal), \code{"always"}.}
\item{polygon_offset}{If non-zero, offsets are added
to the recorded depth of filled polygons. See Details below.}
\item{margin, floating}{Used mainly for text to
draw annotations in the margins, but supported by
most kinds of objects: see \code{\link{mtext3d}}.}
\item{tag}{A length 1 string value. These
may be used to identify objects, or encode other meta
data about the object.}
\item{...}{Any of the arguments above can
be passed to \code{material3d}; see Details below. \code{rgl.material} will ignore others.}
}
\details{
Values can be queried by specifying their names
in a character vector, e.g. \code{material3d("color")}.
There is one read-only property that can be queried
but not set:
\describe{
\item{isTransparent}{Is the current color transparent?}
}
Only one side at a time can be culled.
Object display colors are determined as follows:
\itemize{
\item{If \code{lit = FALSE}, an element of the \code{color} vector property is displayed without modification. See documentation for individual objects for information on which element is chosen.}
\item{If \code{lit = TRUE}, the color is determined as follows.}
\enumerate{
\item{The color is set to the \code{emission} property
of the object. }
\item{For each defined light, the following are added:
\itemize{
\item{the product of the \code{ambient} color
of the light and the \code{ambient} color of the object is added.}
\item{the \code{color} of the
object is multiplied by the \code{diffuse} color
of the light and by a constant depending on
the angle between the surface and the direction to
the light, and added.}
\item{the \code{specular} color of the object
is multiplied by the \code{specular} color of the
light and a constant depending on the \code{shininess}
of the object and the direction to the light, and
added. The \code{shininess} property mainly
determines the size of the shiny highlight; adjust
one or both of the \code{specular} colors to change
its brightness.}
}
}
}
}
The \code{polygon_offset} property is a two element
vector giving the \samp{factor} and \samp{units} values
to use in a \code{glPolygonOffset()} call in OpenGL. If
only one value is given, it is used for both elements.
The \samp{units} value is added to the depth of all pixels in
a filled polygon,
and the \samp{factor} value is multiplied by an estimate of
the slope of the polygon and then added to the depth. Positive values \dQuote{push} polygons back slightly for the purpose
of depth testing, to allow points, lines or other polygons
to be drawn on the surface without being obscured due
to rounding error. Negative values pull the object forward.
A typical value to use is \code{1} (which
is automatically expanded to \code{c(1,1)}).
If values are too large, objects which should be behind
the polygon will show through, and if values are too small,
the objects on the surface will be partially obscured.
Experimentation may be needed to get it right. The first
example in \code{?\link{persp3d}} uses this property to add
grid lines to a surface.
\code{material3d} is an alternate interface to the material properties, modelled after
\code{\link{par3d}}: rather than setting defaults for parameters that are not specified,
they will be left unchanged. \code{material3d} may also be used to query the material
properties; see the examples below.
The current implementation does not return parameters for textures.
The \code{material} member of the \code{\link{r3dDefaults}} list may be used to
set default values for material properties.
The \code{...} parameter to \code{rgl.material} is ignored.
}
\value{
\code{rgl.material()} is called for the side effect of setting the material properties.
It returns a value invisibly which is not intended for use by the user.
Users should use \code{material3d()} to query material properties. It returns values similarly
to \code{\link{par3d}} as follows:
When setting properties, it returns the previous values in a named list. A named list is also
returned when more than one value is queried. When a single value is queried it is returned
directly.
}
\note{
If \code{point_antialias} is \code{TRUE}, points will be drawn as circles in WebGL; otherwise, they
will be drawn as squares. Within R, the behaviour depends
on your graphics hardware: for example, I see circles for
both settings on my laptop.
Within R, lines tend to appear heavier with \code{line_antialias == TRUE}. There's no difference at all
in WebGL.
}
\seealso{
\code{\link{rgl.primitive}},
\code{\link{rgl.bbox}},
\code{\link{rgl.bg}},
\code{\link{rgl.light}}
}
\examples{
save <- material3d("color")
material3d(color = "red")
material3d("color")
material3d(color = save)
# this illustrates the effect of depth_test
x <- c(1:3); xmid <- mean(x)
y <- c(2, 1, 3); ymid <- mean(y)
z <- 1
open3d()
tests <- c("never", "less", "equal", "lequal", "greater",
"notequal", "gequal", "always")
for (i in 1:8) {
triangles3d(x, y, z + i, col = heat.colors(8)[i])
texts3d(xmid, ymid, z + i, paste(i, tests[i], sep = ". "), depth_test = tests[i])
}
highlevel() # To trigger display
}
\keyword{dynamic}
rgl/man/tagged3d.Rd 0000644 0001762 0000144 00000002510 14145464133 013565 0 ustar ligges users \name{tagged3d}
\alias{tagged3d}
\title{
Find tags on rgl objects.
}
\description{
Objects with material properties may have an arbitrary
string set as a tag. This function retrieves the id
values associated with a given tag, or the tags set on
given ids.
}
\usage{
tagged3d(tags = NULL, ids = NULL, full = FALSE, subscene = 0)
}
\arguments{
\item{tags}{
A vector of tags to use for selection.
}
\item{ids}{
A vector of ids to report the tags on.
}
\item{full}{logical; whether to return
a dataframe containing \code{id}, \code{type}, \code{tag},
or a vector of ids or tags.}
\item{subscene}{
Where to look: by default, the whole scene is searched.
\code{NA} restricts the search to the current subscene,
or a subscene id can be given.
}
}
\details{
Exactly one of \code{tags} and \code{ids} must be specified.
}
\value{
A dataframe is constructed with columns
\item{id}{item id}
\item{type}{item type}
\item{tag}{item tag}
matching the specified \code{tags} or \code{ids} value.
If \code{full = TRUE}, the full dataframe is returned, otherwise
just the requested ids or tags.
If \code{ids} is specified, the return value will be
in the same order
as \code{ids}).
}
\author{
Duncan Murdoch
}
\examples{
open3d()
ids <- plot3d(rnorm(10), rnorm(10), rnorm(10), tag = "plot")
unclass(ids)
tagged3d("plot")
tagged3d(ids = ids, full = TRUE)
}
rgl/man/as.mesh3d.rglId.Rd 0000644 0001762 0000144 00000003554 14145464133 014741 0 ustar ligges users \name{as.mesh3d.rglId}
\alias{as.mesh3d.rglId}
\title{
Convert object in plot to RGL mesh object
}
\description{
This method attempts to read the attributes of objects in the
rgl display and construct a mesh3d object to approximate them.
}
\usage{
\method{as.mesh3d}{rglId}(x, type = NA, subscene = NA, ...)
}
\arguments{
\item{x}{
A vector of RGL identifiers of objects in the specified subscene.
}
\item{type}{
A vector of names of types of shapes to convert. Other shapes
will be ignored.
}
\item{subscene}{
Which subscene to look in; the default \code{NA} specifies the
current subscene.
}
\item{\dots}{
Ignored.
}
}
\details{
This function attempts to construct a triangle mesh to approximate
one or more objects from the current display. It can handle objects of types from \code{c("points", "lines", "linestrip", "triangles", "quads", "planes", "surface")}.
Since this method only produces meshes containing points,
segments and triangles, they won't necessarily
be an exact match to the original object.
If the generic \code{\link{as.mesh3d}} is called with no \code{x}
argument, this method will be called with \code{x} set to the
ids in the current scene.
}
\value{
A mesh object.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{as.triangles3d.rglId}} for extracting the triangles,
\code{\link{clipMesh3d}} to apply complex clipping to a mesh object.
}
\examples{
# volcano example taken from "persp"
#
data(volcano)
z <- 2 * volcano # Exaggerate the relief
x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N)
y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W)
zlim <- range(y)
zlen <- zlim[2] - zlim[1] + 1
colorlut <- terrain.colors(zlen) # height color lookup table
col <- colorlut[ z - zlim[1] + 1 ] # assign colors to heights for each point
open3d(useNULL = TRUE)
surface3d(x, y, z, color = col)
m <- as.mesh3d()
close3d()
open3d()
shade3d(m)
}
rgl/man/setUserCallbacks.Rd 0000644 0001762 0000144 00000014076 14100762641 015343 0 ustar ligges users \name{setUserCallbacks}
\alias{setUserCallbacks}
\title{
Set mouse callbacks in R or Javascript code
}
\description{
This function sets user mouse callbacks in R or
\code{\link{rglwidget}} displays.
}
\usage{
setUserCallbacks(button,
begin = NULL,
update = NULL,
end = NULL,
rotate = NULL,
javascript = NULL,
subscene = scene$rootSubscene$id,
scene = scene3d(minimal = FALSE),
applyToScene = TRUE,
applyToDev = missing(scene))
}
\arguments{
\item{button}{
Which button should this callback apply to? Can
be numeric from \code{0:4}, or character from \code{"none", "left", "right", "center", "wheel"}.
}
\item{begin, update, end, rotate}{
Functions to call when events occur. See Details.
}
\item{javascript}{
Optional block of Javascript code to be
included (at the global level).
}
\item{subscene}{
Which subscene do these callbacks apply to?
}
\item{scene}{
Which scene?
}
\item{applyToScene}{
Should these changes apply to the scene object?
}
\item{applyToDev}{
Should these changes apply to the current device?
}
}
\details{
If \code{applyToScene} is \code{TRUE}, this function adds Javascript
callbacks to the \code{scene} object.
If \code{applyToDev} is \code{TRUE}, it adds R
callbacks to the current RGL device.
For Javascript,
the callbacks are specified as strings; these will be
evaluated within the browser in the global context to define the functions,
which will then be called with the Javascript
\code{this} object set to the current
\code{rglwidgetClass} object.
For R, they may be strings or R functions.
Both options may be \code{TRUE}, in which case the
callbacks must be specified as strings which are
both valid Javascript and valid R. The usual way to
do this is to give just a function name, with the
function defined elsewhere, as in the Example below.
The \code{begin} and \code{update} functions should be
of the form
\code{function(x, y) { ... }}. The \code{end} function
will be called with no arguments.
The \code{rotate} callback can only be set on the
mouse wheel. It is called when the mouse
wheel is rotated. It should be of the form
\code{function(away)}, where \code{away} will be 1
while rotating the wheel \dQuote{away} from you,
and 2 while rotating it towards you. If \code{rotate}
is not set but other callbacks are set on the wheel
\dQuote{button}, then each click of the mouse wheel
will trigger all \code{start}, \code{update},
then \code{end} calls in sequence.
The \code{javascript} argument is an optional block
of code which will be evaluated once during the
initialization of the widget. It can define functions
and assign them as members of the \code{window} object,
and then the names of those functions can be given
in the callback arguments; this allows the callbacks
to share information.
}
\value{
Invisibly returns an \code{rglScene} object. This
object will record the changes if \code{applyToScene}
is \code{TRUE}.
If \code{applyToDev} is \code{TRUE}, it will also
have the side effect of attempting to install the
callbacks using \code{\link{rgl.setMouseCallbacks}}
and \code{\link{rgl.setWheelCallback}}.
}
\seealso{
\code{\link{setAxisCallbacks}} for user defined axes.
}
\author{
Duncan Murdoch
}
\examples{
verts <- cbind(rnorm(11), rnorm(11), rnorm(11))
idverts <- plot3d(verts, type = "s", col = "blue")["data"]
# Plot some invisible text; the Javascript will move it
idtext <- text3d(verts[1,,drop = FALSE], texts = 1, adj = c(0.5, -1.5), alpha = 0)
# Define the R functions to use within R
fns <- local({
idverts <- idverts
idtext <- idtext
closest <- -1
update <- function(x, y) {
save <- par3d(skipRedraw = TRUE)
on.exit(par3d(save))
rect <- par3d("windowRect")
size <- rect[3:4] - rect[1:2]
x <- x / size[1];
y <- 1 - y / size[2];
verts <- rgl.attrib(idverts, "vertices")
# Put in window coordinates
vw <- rgl.user2window(verts)
dists <- sqrt((x - vw[,1])^2 + (y - vw[,2])^2)
newclosest <- which.min(dists)
if (newclosest != closest) {
if (idtext > 0)
pop3d(id = idtext)
closest <<- newclosest
idtext <<- text3d(verts[closest,,drop = FALSE], texts = closest, adj = c(0.5, -1.5))
}
}
end <- function() {
if (idtext > 0)
pop3d(id = idtext)
closest <<- -1
idtext <<- -1
}
list(rglupdate = update, rglend = end)
})
rglupdate <- fns$rglupdate
rglend <- fns$rglend
# Define the Javascript functions with the same names to use in WebGL
js <-
' var idverts = \%id\%, idtext = \%idtext\%, closest = -1,
subid = \%subid\%;
window.rglupdate = function(x, y) {
var obj = this.getObj(idverts), i, newdist, dist = Infinity, pt, newclosest;
x = x/this.canvas.width;
y = y/this.canvas.height;
for (i = 0; i < obj.vertices.length; i++) {
pt = obj.vertices[i].concat(1);
pt = this.user2window(pt, subid);
pt[0] = x - pt[0];
pt[1] = y - pt[1];
pt[2] = 0;
newdist = this.vlen(pt);
if (newdist < dist) {
dist = newdist;
newclosest = i;
}
}
if (newclosest !== closest) {
closest = newclosest
var text = this.getObj(idtext);
text.vertices[0] = obj.vertices[closest];
text.colors[0][3] = 1; // alpha is here!
text.texts[0] = (closest + 1).toString();
text.initialized = false;
this.drawScene();
}
};
window.rglend = function() {
var text = this.getObj(idtext);
text.colors[0][3] = 0;
text.initialized = false;
this.drawScene();
}'
js <- sub("\%id\%", idverts, js)
js <- sub("\%subid\%", subsceneInfo()$id, js)
js <- sub("\%idtext\%", idtext, js)
# Install both
setUserCallbacks("left",
begin = "rglupdate",
update = "rglupdate",
end = "rglend",
javascript = js)
rglwidget()
}
rgl/man/tkpar3dsave.Rd 0000644 0001762 0000144 00000003251 14100762641 014331 0 ustar ligges users \name{tkpar3dsave}
\alias{tkpar3dsave}
\alias{par3dsave}
\title{ Modal dialog for saving par3d settings }
\description{
This function opens a TCL/TK modal dialog to allow particular views of an RGL scene
to be saved.
}
\usage{
tkpar3dsave(params = c("userMatrix", "scale", "zoom", "FOV"),
times = FALSE, dev = cur3d(), ...)
}
\arguments{
\item{params}{ Which parameters to save }
\item{times}{ Should times be saved as well? }
\item{dev}{ Which RGL device to work with }
\item{...}{ Additional parameters to pass to \code{\link[tcltk:TkWidgets]{tktoplevel}}}
}
\details{
This opens a TCL/TK modal dialog box with \code{Record} and \code{Quit} buttons. Each time
\code{Record} is clicked, a snapshot is taken of current \code{\link[rgl]{par3d}} settings. When
\code{Quit} is clicked, the dialog closes and the values are returned in a list.
If \code{times == TRUE}, then the times at which the views are recorded will also be saved, so that
the \code{\link[rgl]{play3d}} function will play back with the same timing.
}
\value{
A list of the requested components. Each one will consist of a list of values that were
current when the \code{Record} button was clicked. These are suitable to be passed directly
to the \code{\link[rgl]{par3dinterp}} function.
}
\author{ Duncan Murdoch }
\seealso{ \code{\link{par3d}}, \code{\link{par3dinterp}}}
\examples{
if (interactive() && !in_pkgdown_example()) {
# Record a series of positions, and then play them back immediately
# at evenly spaced times, in an oscillating loop
example(plot3d)
play3d( par3dinterp( tkpar3dsave() ) )
# As above, but preserve the click timings
# play3d( par3dinterp( tkpar3dsave(times=TRUE) ) )
}
}
rgl/man/subscene3d.Rd 0000644 0001762 0000144 00000015672 14145464133 014156 0 ustar ligges users \name{subscene3d}
\alias{subscene3d}
\alias{newSubscene3d}
\alias{currentSubscene3d}
\alias{useSubscene3d}
\alias{addToSubscene3d}
\alias{delFromSubscene3d}
\alias{gc3d}
\title{
Create, select or modify a subscene
}
\description{
This creates a new subscene, or selects one by \code{id} value, or adds objects to one.
}
\usage{
newSubscene3d(viewport = "replace",
projection = "replace",
model = "replace",
mouseMode = "inherit",
parent = currentSubscene3d(),
copyLights = TRUE,
copyShapes = FALSE,
copyBBoxDeco = copyShapes,
copyBackground = FALSE, newviewport,
ignoreExtent)
currentSubscene3d(dev = cur3d())
useSubscene3d(subscene)
addToSubscene3d(ids = tagged3d(tags), tags, subscene = currentSubscene3d())
delFromSubscene3d(ids = tagged3d(tags), tags, subscene = currentSubscene3d())
gc3d(protect = NULL)
}
\arguments{
\item{viewport, projection, model, mouseMode}{
How should the new subscene be embedded? Possible values are
\code{c("inherit", "modify", "replace")}. See Details below.
}
\item{parent}{
The parent subscene (defaults to the current subscene).
}
\item{copyLights, copyShapes, copyBBoxDeco, copyBackground}{
Whether lights, shapes, bounding box decorations and background should be copied to the new subscene.
}
\item{newviewport}{
Optionally specify the new subscene's viewport (in pixels).
}
\item{ignoreExtent}{
Whether to ignore the subscene's bounding box when calculating the parent bounding
box. Defaults to \code{TRUE} if \code{model} is not \code{"inherit"}.
}
\item{dev}{
Which RGL device to query for the current subscene.
}
\item{subscene}{
Which subscene to use or modify.
}
\item{ids}{
A vector of integer object ids to add to the subscene.
}
\item{tags}{
Alternate way to specify \code{ids}. Ignored if \code{ids} is
given.
}
\item{protect}{
Object ids to protect from this garbage collection.
}
}
\details{
The \pkg{rgl} package allows multiple windows to be open; each one corresponds to a \dQuote{scene}.
Within each scene there are one or more \dQuote{subscenes}. Each subscene corresponds
to a rectangular region in the window, and may have its own projection, transformation and behaviour in response to
the mouse.
There is always a current subscene: most graphic operations make changes there, e.g. by adding
an object to it.
The scene \dQuote{owns} objects; \code{addToSubscene3d} and \code{delFromSubscene3d}
put their ids into or remove them from the list being displayed within a particular subscene.
The \code{gc3d} function deletes objects from the scene if they are not visible in any
subscene, unless they are protected by having their id included in \code{protect}.
The \code{viewport}, \code{projection} and \code{model} parameters each have three possible settings:
\code{c("inherit", "modify", "replace")}. \code{"inherit"} means that the corresponding value
from the parent subscene will be used. \code{"replace"} means that the new subscene will
have its own value of the value, independent of its parent. \code{"modify"} means that the
child value will be applied first, and then the parent value will be applied. For viewport, this
means that if the parent viewport is changed, the child will maintain its relative position. For
the two matrices, \code{"modify"} is unlikely to give satisfactory results, but it is available
for possible use.
The \code{mouseMode} parameter
can only be one of \code{c("inherit", "replace")}. If
it is \code{"inherit"}, the subscene will use the mouse
controls of the parent, and any change to them will
affect the parent and all children that inherit from it.
This is the behaviour that was present before \pkg{rgl}
version 0.100.13. If it is \code{"replace"}, then
it will receive a copy of the parent mouse controls,
but modifications to them will affect only this
subscene, not the parent. Note that this is orthogonal
to the \code{\link{par3d}("listeners")} setting:
if another subscene is listed as a listener, it will respond
to mouse actions using the same mode as the one receiving
them.
The \code{viewport} parameter controls the rectangular region in which the subscene is displayed.
It is specified using \code{newviewport} (in pixels relative to the whole window), or set to
match the parent viewport.
The \code{projection} parameter controls settings corresponding to the observer. These
include the field of view and the zoom; they also include the position of the observer relative to
the model. The \code{par3d("projMatrix")} matrix is determined by the projection.
The \code{model} parameter controls settings corresponding to the model. Mouse rotations affect
the model, as does scaling. The \code{par3d("modelMatrix")} matrix is determined by these as
well as by the position of the observer (since OpenGL assumes that the observer is at
(0, 0, 0) after the MODELVIEW transformation). Only those parts concerning the model are
inherited when \code{model} specifies inheritance, the observer setting is controlled by
\code{projection}.
If \code{copyBackground} is \code{TRUE}, the background of the newly created child will
overwrite anything displayed in the parent subscene, regardless of depth.
}
\value{
If successful, each function returns the object id of the subscene, with the exception of
\code{gc3d}, which returns the count of objects which have been deleted,
and \code{useSubscene3d}, which returns the previously active subscene id.
}
\author{
Duncan Murdoch and Fang He.
}
\seealso{
\code{\link{subsceneInfo}} for information about a subscene,
\code{\link{mfrow3d}} and \code{\link{layout3d}} to set up
multiple panes of subscenes.
}
\examples{
# Show the Earth with a cutout by using clipplanes in subscenes
lat <- matrix(seq(90, -90, len = 50)*pi/180, 50, 50, byrow = TRUE)
long <- matrix(seq(-180, 180, len = 50)*pi/180, 50, 50)
r <- 6378.1 # radius of Earth in km
x <- r*cos(lat)*cos(long)
y <- r*cos(lat)*sin(long)
z <- r*sin(lat)
open3d()
obj <- surface3d(x, y, z, col = "white",
texture = system.file("textures/worldsmall.png", package = "rgl"),
specular = "black", axes = FALSE, box = FALSE, xlab = "", ylab = "", zlab = "",
normal_x = x, normal_y = y, normal_z = z)
cols <- c(rep("chocolate4", 4), rep("burlywood1", 4), "darkgoldenrod1")
rs <- c(6350, 5639, 4928.5, 4207, 3486,
(3486 + 2351)/2, 2351, (2351 + 1216)/2, 1216)
for (i in seq_along(rs))
obj <- c(obj, spheres3d(0, 0, col = cols[i], radius = rs[i]))
root <- currentSubscene3d()
newSubscene3d("inherit", "inherit", "inherit", copyShapes = TRUE, parent = root)
clipplanes3d(1, 0, 0, 0)
newSubscene3d("inherit", "inherit", "inherit", copyShapes = TRUE, parent = root)
clipplanes3d(0, 1, 0, 0)
newSubscene3d("inherit", "inherit", "inherit", copyShapes = TRUE, parent = root)
clipplanes3d(0, 0, 1, 0)
# Now delete the objects from the root subscene, to reveal the clipping planes
useSubscene3d(root)
delFromSubscene3d(obj)
}
\keyword{ graphics }
rgl/man/rgl.user2window.Rd 0000644 0001762 0000144 00000004034 14100762641 015155 0 ustar ligges users \name{rgl.user2window}
\alias{rgl.user2window}
\alias{rgl.window2user}
\alias{rgl.projection}
\title{ Convert between RGL user and window coordinates }
\description{
This function converts from 3-dimensional user coordinates
to 3-dimensional window coordinates.
}
\usage{
rgl.user2window(x, y = NULL, z = NULL, projection = rgl.projection())
rgl.window2user(x, y = NULL, z = 0, projection = rgl.projection())
rgl.projection(dev = cur3d(), subscene = currentSubscene3d(dev))
}
\arguments{
\item{x, y, z}{Input coordinates. Any reasonable way of defining the
coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}}
for details.}
\item{projection}{The RGL projection to use }
\item{dev, subscene}{The RGL device and subscene to work with }
}
\details{
These functions convert between user coordinates and window coordinates.
Window coordinates run from 0 to 1 in X, Y, and Z. X runs from 0 on the
left to 1 on the right; Y runs from 0 at the bottom to 1 at the top;
Z runs from 0 foremost to 1 in the background. RGL does not currently
display vertices plotted outside of this range, but in normal circumstances will automatically resize the
display to show them. In the example below this has been suppressed.
}
\value{
The coordinate conversion functions produce a matrix with columns corresponding
to the X, Y, and Z coordinates.
\code{rgl.projection()} returns a list containing the following components:
\item{model}{the modelview matrix}
\item{projection}{the projection matrix}
\item{viewport}{the viewport vector}
See \code{\link{par3d}} for more details.
}
\author{ Ming Chen / Duncan Murdoch}
\seealso{\code{\link{select3d}} }
\examples{
open3d()
points3d(rnorm(100), rnorm(100), rnorm(100))
if (interactive() || !.Platform$OS == "unix") {
# Calculate a square in the middle of the display and plot it
square <- rgl.window2user(c(0.25, 0.25, 0.75, 0.75, 0.25),
c(0.25, 0.75, 0.75, 0.25, 0.25), 0.5)
par3d(ignoreExtent = TRUE)
lines3d(square)
par3d(ignoreExtent = FALSE)
}
}
\keyword{ dynamic }
rgl/man/getBoundary3d.Rd 0000644 0001762 0000144 00000002062 14145464133 014617 0 ustar ligges users \name{getBoundary3d}
\alias{getBoundary3d}
\title{
Extract the boundary of a mesh
}
\description{
Constructs a mesh of line segments corresponding to
non-shared (i.e. boundary) edges of triangles or quads
in the original mesh.
}
\usage{
getBoundary3d(mesh, sorted = FALSE, simplify = TRUE)
}
\arguments{
\item{mesh}{
A mesh object.
}
\item{sorted}{
Whether the result should have the segments sorted in
sequential order.
}
\item{simplify}{
Whether to simplify the resulting mesh, dropping all unused
vertices. If \code{FALSE}, the vertices of the result will
be identical to the vertices of \code{mesh}; if \code{TRUE},
they will likely be different, even if no vertices were dropped.
}
}
\value{
A \code{"mesh3d"} object containing 0 or more segments.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{mesh3d}}
}
\examples{
x <- cube3d()
x$ib <- x$ib[,-(1:2)]
b <- getBoundary3d(x, sorted = TRUE)
open3d()
shade3d(x, alpha=0.2, col = "blue")
shade3d(b)
# Show edge vertices in sequence:
text3d(t(b$vb), text = 1:ncol(b$vb), adj = 0)
c(b$is[1,1], b$is[2,])
}
rgl/man/decorate3d.Rd 0000644 0001762 0000144 00000002156 14145464133 014126 0 ustar ligges users \name{decorate3d}
\alias{decorate3d}
\title{
Add decorations to a 3D plot
}
\description{
\code{decorate3d} adds the usual decorations to a plot: labels, axes, etc.
}
\usage{
decorate3d(xlim = NULL, ylim = NULL, zlim = NULL,
xlab = "x", ylab = "y", zlab = "z",
box = TRUE, axes = TRUE,
main = NULL, sub = NULL,
top = TRUE, aspect = FALSE, expand = 1.03,
tag = material3d("tag"), ...)
}
\arguments{
\item{xlim, ylim, zlim}{These are used
for the labels.}
\item{xlab, ylab, zlab}{labels for the coordinates.}
\item{box, axes}{whether to draw a box and axes.}
\item{main, sub}{main title and subtitle.}
\item{top}{whether to bring the window to the top when done.}
\item{aspect}{either a logical indicating whether to adjust the aspect ratio, or a new ratio.}
\item{expand}{how much to expand the box around the data, if it is drawn.}
\item{tag}{optional label for objects
being produced.}
\item{...}{ignored.}
}
\value{
The RGL id values for those items.
}
\examples{
open3d()
shade3d(tetrahedron3d(), col = "red")
decorate3d(main = "A Tetrahedron")
} rgl/man/aspect3d.Rd 0000644 0001762 0000144 00000002371 14100762640 013611 0 ustar ligges users \name{aspect3d}
\alias{aspect3d}
\title{Set the aspect ratios of the current plot}
\description{
This function sets the apparent ratios of the x, y, and z axes
of the current bounding box.
}
\usage{
aspect3d(x, y = NULL, z = NULL)
}
\arguments{
\item{x}{The ratio for the x axis, or all three ratios, or \code{"iso"} }
\item{y}{The ratio for the y axis }
\item{z}{The ratio for the z axis }
}
\details{
If the ratios are all 1, the bounding box will be displayed as a cube approximately filling the display.
Values may be set larger or smaller as desired. Aspect \code{"iso"} signifies that the
coordinates should all be displayed at the same scale, i.e. the bounding box should not be
rescaled. (This corresponds to the default display before \code{aspect3d} has been called.)
Partial matches to \code{"iso"} are allowed.
\code{aspect3d} works by modifying \code{par3d("scale")}.
}
\value{
The previous value of the scale is returned invisibly.
}
\author{Duncan Murdoch}
\seealso{\code{\link{plot3d}}, \code{\link{par3d}}}
\examples{
x <- rnorm(100)
y <- rnorm(100)*2
z <- rnorm(100)*3
open3d()
plot3d(x, y, z)
aspect3d(1, 1, 0.5)
highlevel() # To trigger display
open3d()
plot3d(x, y, z)
aspect3d("iso")
highlevel()
}
\keyword{dynamic}
rgl/man/callbacks.Rd 0000644 0001762 0000144 00000007603 14100762640 014025 0 ustar ligges users \name{rgl.setMouseCallbacks}
\alias{rgl.setMouseCallbacks}
\alias{rgl.getMouseCallbacks}
\alias{rgl.setWheelCallback}
\alias{rgl.getWheelCallback}
\title{ User callbacks on mouse events }
\description{
Set and get user callbacks on mouse events.
}
\usage{
rgl.setMouseCallbacks(button, begin = NULL, update = NULL, end = NULL,
dev = cur3d(), subscene = currentSubscene3d(dev))
rgl.getMouseCallbacks(button,
dev = cur3d(), subscene = currentSubscene3d(dev))
rgl.setWheelCallback(rotate,
dev = cur3d(), subscene = currentSubscene3d(dev))
rgl.getWheelCallback(dev = cur3d(), subscene = currentSubscene3d(dev))
}
\arguments{
\item{button}{ Which button? Use 1 for left, 2 for
right, 3 for middle, 4 for wheel. Use 0 to set
an action when no button is pressed. }
\item{begin}{ Called when mouse down event occurs }
\item{update}{ Called when mouse moves }
\item{end}{ Called when mouse is released }
\item{rotate}{ Called when mouse wheel is rotated }
\item{dev, subscene}{The RGL device and subscene to work with }
}
\details{
The set functions set event handlers on mouse events that occur within the current RGL window.
The \code{begin} and \code{update} events should be functions taking two arguments; these
will be the mouse coordinates when the event occurs. The \code{end} event handler
takes no arguments. The \code{rotate} event takes a single argument, which will be
equal to \code{1} if the user pushes the wheel away by one click, and \code{2} if
the user pulls the wheel by one click.
Alternatively, the handlers may be set to \code{NULL}, the default value, in which case
no action will occur.
If a subscene has multiple listeners, the user action will still only be called for the
subscene that received the mouse event. It should consult \code{\link{par3d}("listeners")}
if it makes sense to take action on the whole group of subscenes.
The get function retrieves the callbacks that are currently set.
The \dQuote{no button} mouse handler may be set by
specifying \code{button = 0}. The \code{begin}
function will be called the first time the mouse
moves within the subscene, and the \code{update}
function will be called repeatedly as it moves. The
\code{end} function will never be called.
}
\value{
The set functions are called for the side effect of setting the mouse event handlers.
The \code{rgl.getMouseCallbacks} function returns a list containing the callback functions or \code{NULL} if no user callback is set.
The \code{rgl.getWheelCallback} returns the callback function or \code{NULL}.
}
\author{ Duncan Murdoch }
\seealso{ \code{\link{par3d}} to set built-in handlers,
\code{\link{setUserCallbacks}} to work with \code{\link{rglwidget}}.}
\examples{
pan3d <- function(button, dev = cur3d(), subscene = currentSubscene3d(dev)) {
start <- list()
begin <- function(x, y) {
activeSubscene <- par3d("activeSubscene", dev = dev)
start$listeners <<- par3d("listeners", dev = dev, subscene = activeSubscene)
for (sub in start$listeners) {
init <- par3d(c("userProjection","viewport"), dev = dev, subscene = sub)
init$pos <- c(x/init$viewport[3], 1 - y/init$viewport[4], 0.5)
start[[as.character(sub)]] <<- init
}
}
update <- function(x, y) {
for (sub in start$listeners) {
init <- start[[as.character(sub)]]
xlat <- 2*(c(x/init$viewport[3], 1 - y/init$viewport[4], 0.5) - init$pos)
mouseMatrix <- translationMatrix(xlat[1], xlat[2], xlat[3])
par3d(userProjection = mouseMatrix \%*\% init$userProjection, dev = dev, subscene = sub )
}
}
rgl.setMouseCallbacks(button, begin, update, dev = dev, subscene = subscene)
cat("Callbacks set on button", button, "of RGL device", dev, "in subscene", subscene, "\n")
}
open3d()
shade3d(icosahedron3d(), col = "yellow")
# This only works in the internal display...
pan3d(1)
}
\keyword{ dynamic }
rgl/man/pch3d.Rd 0000644 0001762 0000144 00000005016 14100762640 013103 0 ustar ligges users \name{pch3d}
\alias{pch3d}
\title{
Plot symbols similar to base graphics
}
\description{
This function plots symbols similarly to
what the base graphics function \code{\link{points}} does when \code{pch} is specified.
}
\usage{
pch3d(x, y = NULL, z = NULL, pch = 1,
bg = material3d("color")[1], cex = 1, radius,
color = "black", lit = FALSE, ...)
}
\arguments{
\item{x, y, z}{
The locations at which to plot in a form
suitable for use in \code{\link{xyz.coords}}.
}
\item{pch}{
A vector of integers or single characters
describing the symbols to plot.
}
\item{bg}{
The fill color(s) to use for \code{pch} from 21
to 25.
}
\item{cex}{
A relative size of the symbol to plot.
}
\item{radius}{
An absolute size of the symbol to plot
in user coordinates.
}
\item{color}{
The color(s) to use for symbols.
}
\item{lit}{
Whether the object responds to lighting or just shows the
displayed color directly.
}
\item{\dots}{
Other material properties.
}
}
\details{
The list of symbols encoded by numerical
\code{pch} values is given in the \code{\link{points}} help page.
}
\note{
This function is not a perfect match to how the \code{\link{points}} function works due
to limitations in RGL and OpenGL. In
particular:
Symbols with numbers from 1 to 25 are drawn
as 3D sprites (see \code{\link{sprites3d}}),
so they will resize as the window is zoomed.
Letters and numbers from 32 to 255 (which are
mapped to letters) are drawn using \code{\link{text3d}},
so they maintain a fixed size.
A calculation somewhat like the one in \code{\link{plot3d}} that sets the size
of spheres is used to choose the size of
sprites based on \code{cex} and the
current scaling. This will likely need manual
tweaking. Use the \code{radius} argument
for a fixed size.
No special handling is done for the case of
\code{pch = "."}. Use \code{points3d} for
small dots.
As of \pkg{rgl} version 0.100.10, background and foreground
colors can vary from symbol to symbol.
}
\value{
A vector of object id values is returned invisibly. Separate objects will be drawn
for each different combination of \code{pch} value from
0 to 25, \code{color} and \code{bg}, and another holding all the character
symbols.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{points3d}}, \code{\link{text3d}},
\code{\link{plot3d}}, \code{\link{points}}.
}
\examples{
open3d()
i <- 0:25; x <- i \%\% 5; y <- rep(0, 26); z <- i \%/\% 5
pch3d(x, y, z, pch = i, bg = "gray", color = rainbow(26))
text3d(x, y, z + 0.3, i)
pch3d(x + 5, y, z, pch = i+65)
text3d(x + 5, y, z + 0.3, i+65)
}
rgl/man/contourLines3d.Rd 0000644 0001762 0000144 00000014425 14100762640 015021 0 ustar ligges users \name{contourLines3d}
\alias{contourLines3d}
\alias{contourLines3d.rglId}
\alias{contourLines3d.mesh3d}
\alias{filledContour3d}
\alias{filledContour3d.rglId}
\alias{filledContour3d.mesh3d}
\title{
Draw contours on a surface
}
\description{
\code{contourLines3d} draws contour lines on a surface;
\code{filledContour3d} draws filled contours on it.
}
\usage{
contourLines3d(obj, ...)
\method{contourLines3d}{rglId}(obj, ...)
\method{contourLines3d}{mesh3d}(obj, fn = "z",
nlevels = 10,
levels = NULL,
minVertices = 0,
plot = TRUE, ... )
filledContour3d(obj, ...)
\method{filledContour3d}{rglId}(obj, plot = TRUE, replace = plot, ...)
\method{filledContour3d}{mesh3d}(obj, fn = "z",
nlevels = 20,
levels = pretty(range(values), nlevels),
color.palette = function(n) hcl.colors(n, "YlOrRd", rev = TRUE),
col = color.palette(length(levels) - 1),
minVertices = 0,
plot = TRUE,
keepValues = FALSE, ... )
}
\arguments{
\item{obj}{
The object(s) on which to draw contour lines.
}
\item{fn}{
The function(s) to be contoured. See Details.
}
\item{nlevels}{
Suggested number of contour levels if \code{levels} is not given.
}
\item{levels}{
Specified contour values.
}
\item{minVertices}{
See Details below.
}
\item{plot}{
Whether to draw the lines or return them in a dataframe.
}
\item{\dots}{
For the \code{"mesh3d"} methods, additional parameters to pass to \code{\link{segments3d}}
when drawing the contour lines or to \code{\link{shade3d}}
when drawing the filled contours. For the \code{"rglId"}
methods, additional parameters to pass to the \code{"mesh3d"}
methods.
}
\item{replace}{
Whether to delete the objects that are being contoured.
}
\item{color.palette}{a color palette function to
assign colors in the plot}
\item{col}{the actual colors to use in the plot.}
\item{keepValues}{whether to save the function values at
each vertex when \code{plot = FALSE}}
}
\details{
For \code{contourLines3d}, the \code{fn} argument can be any
of the following:
\itemize{
\item{ a character vector naming
one or more functions}
\item{a function}
\item{a numeric vector with one value per vertex}
\item{\code{NULL}, indicating that the numeric values
are saved in \code{obj$values}}
\item{a list containing any of the above.}
}
For \code{filledContour3d}, only one function can be specified.
The special names \code{"x", "y", "z"} may be used in
\code{fn} to specify functions returning one of those
coordinates. (If you have existing functions \code{x()}, \code{y()}
or \code{z()} they will be masked by this choice; specify
such functions by value rather than name, e.g. \code{fn = x}
instead of \code{fn = "x"}.)
Functions in \code{fn} with formal arguments \code{x},
\code{y} and \code{z} will receive the coordinates of
vertices in those arguments, otherwise they will receive
the coordinates in a single n x 3 matrix. They should
be vectorized and return one value per vertex.
Each of the functions will be evaluated at each vertex
of the surface specified by \code{obj}, and contours will
be drawn assuming the function is linear between vertices.
If contours of a nonlinear function are needed, you may
want to increase \code{minVertices} as described below.
If \code{levels} is not specified, values will be set
separately for each entry in \code{fn}, using
\code{pretty(range(values, na.rm = TRUE), nlevels)} where
\code{values} are the values on the vertices.
The \code{minVertices} argument is used to improve the
approximation to the contour when the function is non-linear.
In that case, the interpolation between vertices
can be inaccurate. If \code{minVertices} is set to a
positive
number (e.g. \code{10000}), then the mesh is modified
by subdivision to have at least that number of vertices,
so that pieces are smaller and the linear interpolation
is more accurate.
}
\note{
To draw contours on a surface, the surface should be drawn
with material property \code{polygon_offset = 1} (or perhaps
some larger positive value) so that the lines of the contour are not
obscured by the surface.
In R versions prior to 3.6.0, the default \code{color.palette}
is \code{grDevices::cm.colors}.
}
\value{
For both \code{contourLines3d} and \code{filledContour3d}
the \code{"rglId"} method converts the given id values to
a mesh, and calls the \code{"mesh3d"} method.
The \code{"mesh3d"} method returns an object of class
\code{"rglId"} corresponding to what was
drawn if \code{plot} is \code{TRUE},
If \code{plot} is \code{FALSE}, \code{contourLines3d} returns a dataframe containing
columns \code{c("x", "y", "z", "fn", "level")} giving
the coordinates of the endpoints of each line segment,
the name (or index) of the function for this contour, and the
level of the contour.
If \code{plot} is \code{FALSE}, \code{filledContour3d}
returns a \code{"\link{mesh3d}"} object holding the result.
If \code{keepValues} is \code{TRUE}, the mesh
will contain the values corresponding to each vertex
(with linear approximations at the boundaries).
}
\author{
Duncan Murdoch
}
\seealso{
The \pkg{misc3d} package contains the function \code{\link[misc3d]{contour3d}}
to draw contour surfaces in space instead of contour lines
on surfaces.
}
\examples{
# Add contourlines in "z" to a persp plot
z <- 2 * volcano # Exaggerate the relief
x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N)
y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W)
open3d()
id <- persp3d(x, y, z, aspect = "iso",
axes = FALSE, box = FALSE, polygon_offset = 1)
contourLines3d(id) # "z" is the default function
filledContour3d(id, polygon_offset = 1, nlevels = 10, replace = TRUE)
# Draw longitude and latitude lines on a globe
lat <- matrix(seq(90, -90, len = 50)*pi/180, 50, 50, byrow = TRUE)
long <- matrix(seq(-180, 180, len = 50)*pi/180, 50, 50)
r <- 6378.1 # radius of Earth in km
x <- r*cos(lat)*cos(long)
y <- r*cos(lat)*sin(long)
z <- r*sin(lat)
open3d()
ids <- persp3d(x, y, z, col = "white",
texture = system.file("textures/worldsmall.png", package = "rgl"),
specular = "black", axes = FALSE, box = FALSE, xlab = "", ylab = "", zlab = "",
normal_x = x, normal_y = y, normal_z = z, polygon_offset = 1)
contourLines3d(ids, list(latitude = function(x, y, z) asin(z/sqrt(x^2+y^2+z^2))*180/pi,
longitude = function(x, y, z) atan2(y, x)*180/pi))
}
rgl/man/propertySetter.Rd 0000644 0001762 0000144 00000007231 14100762641 015157 0 ustar ligges users \name{propertySetter}
\alias{propertySlider}
\alias{propertySetter}
\alias{par3dinterpSetter}
\alias{matrixSetter}
\alias{vertexSetter}
\title{
Obsolete functions to write HTML/Javascript code to control a WebGL display
}
\description{ These functions write
out HTML code to control WebGL displays based
using the obsolete \code{writeWebGL}. Use
\code{\link{playwidget}} and related functions instead.
}
\usage{
propertySlider(setter = propertySetter,
minS = NULL, maxS = NULL, step = 1, init = NULL,
labels,
id = basename(tempfile("input")), name = id,
outputid = paste0(id, "text"),
index = NULL,
...)
propertySetter(values = NULL, entries, properties, objids, prefixes = "",
param = seq_len(NROW(values)), interp = TRUE, digits = 7)
par3dinterpSetter(fn, from, to, steps, subscene, omitConstant = TRUE,
rename = character(), ...)
matrixSetter(fns, from, to, steps, subscene = currentSubscene3d(),
matrix = "userMatrix", omitConstant = TRUE, prefix = "", ...)
vertexSetter(values, vertices = 1, attributes, objid, prefix = "",
param = seq_len(NROW(values)), interp = TRUE,
digits = 7)
}
\arguments{
\item{setter}{A function to write Javascript code, or its output, or
a list containing several of these.}
\item{minS, maxS, step, init}{Slider values to be displayed. Reasonable defaults are used if missing.}
\item{labels}{Labels to display for each slider value. The
defaults are calculated using internal variables. If \code{NULL},
no labels will be shown.}
\item{id}{The \code{id} of the input control that will be generated.}
\item{name}{The name of the input control that will be generated.}
\item{outputid}{The \code{id} of the output control that
will display the slider value, or \code{NULL} for none.}
\item{index}{The 1-based index of this slider: it controls the
corresponding entry in an indexed setter such as \code{matrixSetter}.}
\item{...}{Other parameters.}
\item{values}{An array of values; rows correspond to slider positions. Alternatively, \code{NULL}; the generated function takes a
single value or array of values and applies them directly.}
\item{entries, properties, objids, prefixes}{Vectors describing
the columns of \code{values}.}
\item{param}{Parameter values corresponding to each row of \code{values}.}
\item{interp}{Whether to interpolate values. If \code{FALSE},
the Javascript function will expect non-negative integer values.
Ignored if \code{values} is \code{NULL}.}
\item{digits}{How many significant digits to emit in the Javascript code.}
\item{fn}{A function returned from \code{\link{par3dinterp}}.}
\item{from, to, steps}{Values where \code{fn} should be evaluated.}
\item{subscene}{Which subscene's properties should be modified?}
\item{omitConstant}{If \code{TRUE}, do not set values that are
constant across the range.}
\item{rename}{A named character vector of names of Javascript properties
to modify.}
\item{fns}{A list containing functions returned from
\code{\link{par3dinterp}}.}
\item{matrix}{A character string giving the Javascript property
name of the matrix to modify.}
\item{prefix}{The prefix of the scene containing \code{matrix}.}
\item{vertices}{A vector of vertex numbers (1-based) within
an object.}
\item{attributes}{A vector of attributes of a vertex,
from \code{c("x", "y", "z", "r", "g", "b", "a", "nx", "ny", "nz",
"radius", "ox", "oy", "oz", "ts", "tt")}.}
\item{objid}{The object containing the vertices to be modified.}
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{rglwidget}}, \code{\link{playwidget}}
}
rgl/man/writePLY.Rd 0000644 0001762 0000144 00000005674 14145464133 013640 0 ustar ligges users \name{writePLY}
\alias{writePLY}
\title{
Write Stanford PLY format files
}
\description{
This function writes PLY files. This is a simple file format that
is commonly used in 3D printing. It does not represent text,
only edges and polygons. The \code{writePLY} function
does the necessary conversions.
}
\usage{
writePLY(con, format = c("little_endian", "big_endian", "ascii"),
pointRadius = 0.005, pointShape = icosahedron3d(),
lineRadius = pointRadius, lineSides = 20,
pointsAsEdges = FALSE, linesAsEdges = pointsAsEdges,
withColors = TRUE, withNormals = !(pointsAsEdges || linesAsEdges),
ids = tagged3d(tags), tags = NULL)
}
\arguments{
\item{con}{
A connection or filename.
}
\item{format}{
Which output format. Defaults to little-endian binary.
}
\item{pointRadius, lineRadius}{
The radius of points and lines relative to the overall scale of the figure,
if they are converted to polyhedra.
}
\item{pointShape}{
A mesh shape to use for points if they are converted. It is scaled by the \code{pointRadius}.
}
\item{lineSides}{
Lines are rendered as cylinders with this many sides.
}
\item{pointsAsEdges, linesAsEdges}{
Whether to convert points and lines to \dQuote{Edge} records in the PLY output.
}
\item{withColors}{
Whether to output vertex color information.
}
\item{withNormals}{
Whether to output vertex normals for smooth shading.
}
\item{ids}{
The identifiers (from \code{\link{ids3d}}) of the
objects to write. If \code{NULL}, try to write everything.
}
\item{tags}{
Select objects with matching tags. Ignored
if \code{ids} is specified.
}
}
\details{
The current implementation only outputs triangles, quads, planes, spheres,
points, line segments, line strips and surfaces.
The defaults for \code{pointsAsEdges} and \code{linesAsEdges} have been
chosen because Blender (\url{https://www.blender.org}) does not import
lines, only polygons. If you are exporting to other software you
may want to change them.
Since the PLY format only allows one object per file, all RGL objects
are combined into a single object when output.
The output file is readable by Blender and Meshlab; the latter can write in
a number of other formats, including U3D, suitable for import into a PDF document.
}
\value{
Invisibly returns the name of the connection to which the
data was written.
}
\references{
The file format was found on \url{https://www.mathworks.com} on November 10, 2012
at a URL that no longer exists; currently the
format is described at \url{https://www.mathworks.com/help/vision/ug/the-ply-format.html}.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{scene3d}} saves a copy of a scene to an R variable;
\code{\link{rglwidget}}, \code{\link{writeASY}}, \code{\link{writeOBJ}} and \code{\link{writeSTL}}
write the scene to a file in various other formats.
}
\examples{
filename <- tempfile(fileext = ".ply")
open3d()
shade3d( icosahedron3d(col = "magenta") )
writePLY(filename)
}
\keyword{ graphics }
rgl/man/rglShared.Rd 0000644 0001762 0000144 00000006336 14137472630 014032 0 ustar ligges users \name{rglShared}
\alias{rglShared}
\title{
Create shared data from an RGL object
}
\description{
The \pkg{crosstalk} package provides a way for
different parts of an interactive display to
communicate about datasets, using \dQuote{shared data} objects. When selection or filtering
is performed in one view, the result is mirrored
in all other views.
This function allows vertices of RGL objects
to be treated as shared data.
}
\usage{
rglShared(id, key = NULL, group = NULL,
deselectedFade = 0.1,
deselectedColor = NULL,
selectedColor = NULL,
selectedIgnoreNone = TRUE,
filteredFade = 0,
filteredColor = NULL)
}
\arguments{
\item{id}{
An existing RGL id.
}
\item{key}{
Optional unique labels to apply to each vertex.
If missing, numerical keys will be used.
}
\item{group}{
Optional name of the shared group to which
this data belongs. If missing, a random name
will be generated.
}
\item{deselectedFade, deselectedColor}{
Appearance of points that are not selected. See Details.
}
\item{selectedColor}{
Appearance of points that are selected.
}
\item{selectedIgnoreNone}{
If no points are selected, should the points be shown
in their original colors (\code{TRUE}), or in the
deselected colors (\code{FALSE})?
}
\item{filteredFade, filteredColor}{
Appearance of points that have been filtered out.
}
}
\details{
Some functions which normally work on
dataframe-like datasets will accept shared data
objects in their place.
If a selection is in progress, the alpha value for
unselected points is multiplied by \code{deselectedFade}.
If \code{deselectedColor} is \code{NULL}, the color is left
as originally specified; if not, the point is changed to
the color given by \code{deselectedColor}.
If no points have been selected, then by default points
are shown in their original colors. However, if
\code{selectedIgnoreNone = FALSE}, all points are displayed
as if unselected.
The \code{selectedColor} argument is similarly used to
change the color (or not) of selected points, and \code{filteredFade}
and \code{filteredColor} are used for points that
have been filtered out of the display.
}
\value{
An object of class \code{"SharedData"} (from the
optional \pkg{crosstalk} package) which
contains the x, y and z coordinates of the RGL object
with the given \code{id}.
}
\references{
\url{https://rstudio.github.io/crosstalk/index.html}
}
\author{
Duncan Murdoch
}
\examples{
save <- options(rgl.useNULL = TRUE)
open3d()
x <- sort(rnorm(100))
y <- rnorm(100)
z <- rnorm(100) + atan2(x, y)
ids <- plot3d(x, y, z, col = rainbow(100))
# The data will be selected and filtered, not the axes.
sharedData <- rglShared(ids["data"])
# Also add some labels that are only displayed
# when points are selected
sharedLabel <- rglShared(text3d(x, y, z, text = 1:100,
adj = -0.5),
group = sharedData$groupName(),
deselectedFade = 0,
selectedIgnoreNone = FALSE)
if (interactive() || in_pkgdown_example())
crosstalk::filter_slider("x", "x", sharedData, ~x) \%>\%
rglwidget(shared = list(sharedData, sharedLabel), controller = .) \%>\%
rglMouse()
options(save)
} rgl/man/surface3d.Rd 0000644 0001762 0000144 00000004753 14100762641 013771 0 ustar ligges users \name{surface3d}
\title{Add surface}
\alias{surface3d}
\alias{terrain3d}
\description{
Adds a surface to the current scene. The surface is defined by
a matrix defining the height of each grid point and two vectors
defining the grid.
}
\usage{
surface3d(x, y, z, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL)
terrain3d(x, y, z, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL)
}
\arguments{
\item{ x }{
values corresponding to rows of \code{z}, or matrix of x coordinates
}
\item{ y }{
values corresponding to the columns of \code{z}, or matrix of y coordinates
}
\item{ z }{
matrix of heights
}
\item{ ... }{Material and texture properties. See \code{\link{rgl.material}} for details.}
\item{normal_x, normal_y, normal_z}{
matrices of the same dimension as \code{z} giving the coordinates of normals at
each grid point}
}
\details{
Adds a surface mesh to the current scene. The surface is defined by
the matrix of height values in \code{z}, with rows corresponding
to the values in \code{x} and columns corresponding to the values in
\code{y}. This is the same parametrization as used in \code{\link{persp}}.
If the \code{x} or \code{y} argument is a matrix, then it must be of the same
dimension as \code{z}, and the values in the matrix will be used for the corresponding
coordinates. This is used to plot shapes such as cylinders
where z is not a function of x and y.
If the normals are not supplied, they will be calculated automatically based
on neighbouring points.
\code{surface3d} always draws the surface with the `front' upwards
(i.e. towards higher \code{z} values). This can be used to render
the top and bottom differently; see \code{\link{rgl.material}} and
the example below.
For more flexibility in defining the surface, use \code{\link{rgl.surface}}.
\code{surface3d} and \code{terrain3d} are synonyms.
}
\examples{
#
# volcano example taken from "persp"
#
z <- 2 * volcano # Exaggerate the relief
x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N)
y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W)
zlim <- range(z)
zlen <- zlim[2] - zlim[1] + 1
colorlut <- terrain.colors(zlen) # height color lookup table
col <- colorlut[ z - zlim[1] + 1 ] # assign colors to heights for each point
open3d()
surface3d(x, y, z, color = col, back = "lines")
}
\seealso{
\code{\link{rgl.material}}, \code{\link{rgl.surface}}.
See \code{\link{persp3d}} for a higher level interface.
}
\keyword{dynamic}
rgl/man/as.rglscene.Rd 0000644 0001762 0000144 00000000701 14145464133 014307 0 ustar ligges users \name{as.rglscene}
\alias{as.rglscene}
\title{
Convert an object to an rglscene object.
}
\description{
This is a placeholder generic function, to allow other
packages to create \code{"rglscene"} objects compatible with
the objects produced by \code{\link{scene3d}}.
No methods are currently defined in \pkg{rgl}.
}
\usage{
as.rglscene(x, ...)
}
\arguments{
\item{x}{
Object to convert.
}
\item{\dots}{
Other parameters to pass to methods.
}
}
rgl/man/thigmophobe3d.Rd 0000644 0001762 0000144 00000004425 14100762641 014642 0 ustar ligges users \name{thigmophobe3d}
\alias{thigmophobe3d}
\title{
Find the direction away from the closest point in a 3d projection
}
\description{
Jim Lemon's \code{\link[plotrix]{thigmophobe}} function in the
\code{\link[plotrix:plotrix-package]{plotrix}} package
computes good directions for labels in a 2D plot. This function
does the same for a particular projection in a 3D plot by
projecting down to 2D and calling his function.
}
\usage{
thigmophobe3d(x, y = NULL, z = NULL,
P = par3d("projMatrix"),
M = par3d("modelMatrix"),
windowRect = par3d("windowRect"))
}
\arguments{
\item{x, y, z}{point coordinates. Any reasonable way of defining
the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details.
}
\item{P, M, windowRect}{
The projection and modelview matrices, and the size and position of
the display in pixels.
}
}
\details{
Since \code{thigmophobe3d} projects using fixed \code{P} and \code{M},
it will not necessarily choose good directions if the user rotates
the display or makes any other change to the projection.}
\note{
The example
below shows how to update the directions during an animation;
I find that the moving labels are distracting, and prefer to live with
fixed ones.
}
\value{
A vector of values from 1 to 4 to be used as the \code{pos} argument
in \code{\link{text3d}}.
}
\references{
\CRANpkg{plotrix}
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{text3d}}
}
\examples{
if (requireNamespace("plotrix", quietly = TRUE)) {
# Simulate some data
xyz <- matrix(rnorm(30), ncol = 3)
# Plot the data first, to establish the projection
plot3d(xyz)
# Now thigmophobe3d can choose directions
textid <- text3d(xyz, texts = 1:10, pos = thigmophobe3d(xyz))
# Update the label positions during an animation
if (interactive() && !rgl.useNULL()) {
spin <- spin3d(rpm = 5)
f <- function(time) {
par3d(skipRedraw = TRUE)
on.exit(par3d(skipRedraw = FALSE))
pop3d(id = textid)
# Need to rotate before thigmophobe3d is called
result <- spin(time)
par3d(userMatrix = result$userMatrix)
textid <<- text3d(xyz, texts = 1:10, pos = thigmophobe3d(xyz))
result
}
play3d(f, duration = 5)
} else
textid # just print the static display
}
}
rgl/man/clipMesh3d.Rd 0000644 0001762 0000144 00000012722 14145464133 014104 0 ustar ligges users \name{clipMesh3d}
\alias{clipMesh3d}
\alias{clipObj3d}
\title{
Clip mesh or RGL object to general region
}
\description{
Modifies a mesh3d object so that values of
a function are bounded.
}
\usage{
clipMesh3d(mesh, fn, bound = 0, greater = TRUE,
minVertices = 0, plot = FALSE, keepValues = FALSE)
clipObj3d(ids = tagged3d(tags), fn, bound = 0, greater = TRUE,
minVertices = 0,
replace = TRUE, tags)
}
\arguments{
\item{mesh}{
A \code{\link{mesh3d}} object.
}
\item{fn}{
A function used to determine clipping, or a vector of values from such
a function, with one value per vertex.
}
\item{bound}{
The value(s) of \code{fn} on the clipping boundary.
}
\item{greater}{
Logical; whether to keep \code{fn >= bound} or not.
}
\item{minVertices}{
See Details below.
}
\item{plot}{Logical; whether or not to plot the mesh.}
\item{keepValues}{Logical; whether to save the function values at
each vertex when \code{plot = FALSE}.}
\item{ids}{
The RGL id value(s) of objects to clip.
}
\item{tags}{
Alternate way to specify \code{ids}. Ignored if \code{ids} is
given.
}
\item{replace}{
Should the \code{ids} objects be deleted after the clipped
ones are drawn?
}
}
\details{
These functions transform a mesh3d object or other
RGL objects by removing parts where \code{fn} violates
the bound.
For \code{clipMesh3d} the \code{fn} argument can be any
of the following:
\itemize{
\item{a character vector naming a function (with special
names \code{"x"}, \code{"y"}, and \code{"z"} corresponding
to functions returning those coordinates)}
\item{a function}
\item{a numeric vector with one value per vertex}
\item{\code{NULL}, indicating that the numeric values
are saved in \code{mesh$values}}
}
For \code{clipObj3d} any of the above except \code{NULL}
may be used.
If \code{fn}
is a numeric vector, with one value per vertex, those values will be
used in the test.
If it is a function with formal arguments \code{x},
\code{y} and \code{z}, it will receive the coordinates of
vertices in those arguments, otherwise it will receive
the coordinates in a single n x 3 matrix. The function
should be vectorized and return one value per vertex,
to check against the bound.
These operations are performed on the mesh:
First, all quads are converted to triangles.
Next, each vertex is checked against the condition.
Modifications to triangles depend
on how many of the vertices satisfy the condition
(\code{fn >= bound} or \code{fn <= bound}, depending on \code{greater})
for inclusion.
\itemize{
\item If no vertices in a triangle satisfy the condition, the triangle is omitted.
\item If one vertex satisfies the condition, the other two vertices
in that triangle are shrunk towards it by assuming \code{fn}
is locally linear.
\item If two vertices satisfy the condition, the third vertex
is shrunk along each edge towards each other vertex, forming a
quadrilateral made of two new triangles.
\item If all vertices satisfy the condition, they are included
with no modifications.
}
Modifications to line segments are similar: the segment
will be shortened if it crosses the boundary, or omitted
if it is entirely out of bounds. Points, spheres, text
and sprites will just be kept or rejected.
The \code{minVertices} argument is used to improve the
approximation to the boundary when \code{fn} is a non-linear
function. In that case, the interpolation described above
can be inaccurate. If \code{minVertices} is set to a
positive
number (e.g. \code{10000}), then each object is modified
by subdivision to have at least that number of vertices,
so that pieces are smaller and the linear interpolation
is more accurate. In the \code{clipObj3d} function,
\code{minVertices} can be a vector, with entries corresponding
to each of the entries in \code{ids}.
}
\value{
If \code{plot = FALSE},
\code{clipMesh3d} returns new mesh3d object in which all vertices (approximately) satisfy the
clipping condition. Note that the order of vertices will likely
differ from the original order, and new vertices will be added near
the boundary (and if \code{minVertices > 0}, in the
interior). If in addition \code{keepValues = TRUE},
a component named \code{"values"} will be added to the
mesh containing the values for each vertex.
If \code{plot = TRUE}, the result will be
plotted with \code{\link{shade3d}} and its result returned.
\code{clipObj3d} is called for the side effect of modifying
the scene. It returns a list of new RGL id values
corresponding to the \code{ids} passed as arguments.
}
\author{
Duncan Murdoch
}
\references{
See \url{https://stackoverflow.com/q/56242470/2554330} for a
motivating example.
}
\seealso{
See \code{\link{contourLines3d}} and
\code{\link{filledContour3d}} for ways to display function
values without clipping.
}
\examples{
# Show the problem that minVertices solves:
cube <- cube3d(col = "red")
# This function only has one argument, so it will
# be passed x, y and z in columns of a matrix
vecnorm <- function(vals) apply(vals, 1, function(row) sqrt(sum(row^2)))
open3d()
mfrow3d(2, 2, sharedMouse = TRUE)
id1 <- shade3d(cube)
# All vertices have norm sqrt(3), so this clips nothing:
clipObj3d(id1, fn = vecnorm, bound = sqrt(2))
next3d()
id2 <- wire3d(cube, lit = FALSE)
clipObj3d(id2, fn = vecnorm, bound = sqrt(2))
# This subdivides the cube, and does proper clipping:
next3d()
id3 <- shade3d(cube)
clipObj3d(id3, fn = vecnorm, bound = sqrt(2), minVertices = 200)
next3d()
id4 <- wire3d(cube, lit = FALSE)
clipObj3d(id4, fn = vecnorm, bound = sqrt(2), minVertices = 200)
}
rgl/man/tkrgl.Rd 0000644 0001762 0000144 00000002222 14100762641 013222 0 ustar ligges users \name{tkrgl}
\alias{tkrgl}
\title{
The former tkrgl package
}
\description{
Functions from the former \pkg{tkrgl} package.
}
\details{
The \pkg{tkrgl} package contained functions to use TCL/TK to control
an RGL scene on screen. These functions have now been merged
into the \pkg{rgl} package, and the \pkg{tkrgl} package has
been archived.
To avoid conflicts with RGL names and to indicate the TCL/TK
nature of these functions, they have all been prefixed with \code{tk}:
\describe{
\item{\code{\link{tkpar3dsave}}}{Formerly \code{tkrgl::par3dsave}, allows interactive
saving of scene parameters.}
\item{\code{\link{tkspin3d}, \link{tkspinControl}}}{Formerly
\code{tkrgl::spin3d} and \code{tkrgl::spinControl}, create buttons
to spin the scene.}
}
History:
\tabular{ll}{
0.2-2 \tab First public release \cr
0.3 \tab Added possibility to control multiple windows \cr
0.4 \tab Compatibility with 2.0.0 tcltk package \cr
0.5 \tab Added continuous rotation \cr
0.6 \tab Added par3dsave \cr
0.7 \tab Added parameters to \code{\link{tkspinControl}}, fixed startup \cr
0.8 \tab Minor fixes to pass checks \cr
0.9 \tab Merge functions into \pkg{rgl} \cr
}
}
rgl/man/writeASY.Rd 0000644 0001762 0000144 00000007061 14145464133 013620 0 ustar ligges users \name{writeASY}
\alias{writeASY}
\title{
Write Asymptote code for an RGL scene
}
\description{
Asymptote is a language for 3D graphics that
is highly integrated with LaTeX. This is
an experimental function to
write an Asymptote program to approximate
an RGL scene.
}
\usage{
writeASY(scene = scene3d(),
title = "scene",
outtype = c("pdf", "eps", "asy", "latex", "pdflatex"),
prc = TRUE,
runAsy = "asy \%filename\%",
defaultFontsize = 12,
width = 7, height = 7,
ppi = 100,
ids = tagged3d(tags),
tags = NULL,
version = "2.65")
}
\arguments{
\item{scene}{RGL scene object}
\item{outtype}{
What type of file to write? See Details.
}
\item{prc}{
Whether to produce an interactive PRC scene.
}
\item{title}{
The base of the filename to produce.
}
\item{runAsy}{
Code to run the Asymptote program.
}
\item{defaultFontsize}{
The default fontsize for text.
}
\item{width, height}{
Width and height of the output image, in inches.
}
\item{ppi}{
\dQuote{Pixels per inch} to assume when converting
line widths and point sizes (which RGL measures in
pixels).
}
\item{ids}{
If not \code{NULL}, write out just these
RGL objects.
}
\item{tags}{
Alternate way to specify \code{ids}. Ignored if \code{ids} is
given.
}
\item{version}{
Asymptote version 2.44 had a definition for its \dQuote{light()} function
that was incompatibly changed in versions 2.47 and 2.50.
The current code has been tested with version 2.65.
If you are using an older version, set \code{version}
to your version number and it may work better.
}
}
\details{
Asymptote is both a language describing a
2D or 3D graphic, and a program to interpret
that language and produce output in a variety
of formats including EPS, PDF (interactive
or static), etc.
The interactive scene produced with \code{prc = TRUE}
requires \code{outtype = "pdf"}, and (as of this
writing) has a number of limitations:
\itemize{
\item{As far as we know, only Adobe Acrobat Reader of a sufficiently recent version can display
these scenes.}
\item{Current versions ignore lighting settings.}
}
}
\value{
The filename of the output file is returned
invisibly.
}
\references{
J. C. Bowman and A. Hammerlindl (2008). Asymptote: A vector graphics language,
TUGBOAT: The Communications of the TeX Users Group, 29:2, 288-294.
}
\author{
Duncan Murdoch
}
\note{
This function is currently under development and limited in the quality
of output it produces. Arguments will likely
change.
There are a number of differences between the interactive display in
Asymptote and the display in RGL. In particular, many objects that are
a fixed size in RGL will scale with the image in Asymptote. Defaults
have been chosen somewhat arbitrarily; tweaking will likely be needed.
Material properties of surfaces are not yet implemented.
On some systems, the program \command{asy} used
to process the output has bugs and may fail. Run the example
at your own risk!
}
\seealso{
\code{\link{scene3d}} saves a copy of a scene to an R variable; \code{\link{rglwidget}},
\code{\link{writePLY}}, \code{\link{writeOBJ}} and \code{\link{writeSTL}}
write the scene to a file in various other formats.
}
\examples{
\dontrun{
# On some systems, the program "asy" used
# to process the output has bugs, so this may fail.
x <- rnorm(20)
y <- rnorm(20)
z <- rnorm(20)
plot3d(x, y, z, type = "s", col = "red")
olddir <- setwd(tempdir())
writeASY(title = "interactive") # Produces interactive.pdf
writeASY(title = "noninteractive", prc = FALSE) # Produces noninteractive.pdf
setwd(olddir)
}
}
rgl/man/cube3d.Rd 0000644 0001762 0000144 00000002650 14100762640 013250 0 ustar ligges users \name{cube3d}
\alias{cube3d}
\alias{oh3d}
\alias{tetrahedron3d}
\alias{octahedron3d}
\alias{icosahedron3d}
\alias{dodecahedron3d}
\alias{cuboctahedron3d}
\title{Sample 3D mesh objects}
\description{
A collection of sample mesh objects.
}
\usage{
cube3d(trans = identityMatrix(), ...)
tetrahedron3d(trans = identityMatrix(), ...)
octahedron3d(trans = identityMatrix(), ...)
icosahedron3d(trans = identityMatrix(), ...)
dodecahedron3d(trans = identityMatrix(), ...)
cuboctahedron3d(trans = identityMatrix(), ...)
oh3d(trans = identityMatrix(), ...) # an 'o' object
}
\arguments{
\item{trans}{transformation to apply to objects}
\item{...}{additional parameters to pass to \code{\link{mesh3d}}}
}
\details{
These sample objects optionally take a 4x4 matrix transformation \code{trans} as
an argument. This transformation is applied to all vertices of the default shape.
The default is an identity transformation.
}
\value{
Objects of class \code{c("mesh3d",
"shape3d")}.
}
\examples{
# render all of the Platonic solids
open3d()
shade3d( translate3d( tetrahedron3d(col = "red"), 0, 0, 0) )
shade3d( translate3d( cube3d(col = "green"), 3, 0, 0) )
shade3d( translate3d( octahedron3d(col = "blue"), 6, 0, 0) )
shade3d( translate3d( dodecahedron3d(col = "cyan"), 9, 0, 0) )
shade3d( translate3d( icosahedron3d(col = "magenta"), 12, 0, 0) )
}
\seealso{
\code{\link{mesh3d}}
}
\keyword{dynamic}
rgl/man/rglIds.Rd 0000644 0001762 0000144 00000003447 14100762641 013335 0 ustar ligges users \name{rglIds}
\alias{lowlevel}
\alias{highlevel}
\alias{rglId}
\alias{rglLowlevel}
\alias{rglHighlevel}
\alias{print.rglId}
\title{
RGL id values
}
\description{
All objects in an RGL scene have a
numerical id. These ids are normally stored
in vectors of class \code{c("rglIds", "numeric")}, which
will also have class \code{"rglHighlevel"}
or \code{"rglLowlevel"} depending on
whether a high level function like
\code{\link{plot3d}} or \code{\link{persp3d}}, or a low level function created the objects.
}
\usage{
rglId(ids = integer())
lowlevel(ids = integer())
highlevel(ids = integer())
\method{print}{rglId}(x,
rglwidget = getOption("rgl.printRglwidget", FALSE),
...)
}
\arguments{
\item{ids}{
A vector of object ids.
}
\item{x}{
An \code{"rglId"} object to print.
}
\item{rglwidget}{
Whether to create and print an RGL widget.
If false, nothing is printed.
}
\item{...}{
Other arguments which will be passed to
\code{\link{rglwidget}} if it is used.
}
}
\details{
These functions and classes are intended to allow
RGL scenes to be automatically
displayed in R Markdown documents. See \code{\link{setupKnitr}} for details on enabling auto-printing.
Note that \emph{all} objects in the current
scene will be printed by default, not just
the ids in \code{x}. (One reason for this
is that lights are also objects; printing
objects without lights would rarely make
sense.)
}
\value{
Objects of class \code{"rglId"}, \code{c("rglHighlevel", "rglId",
"numeric")} or \code{c("rglLowlevel", "rglId",
"numeric")} for \code{rglId}, \code{lowlevel} or \code{highlevel}
respectively.
}
\author{
Duncan Murdoch
}
\examples{
x <- matrix(rnorm(30), ncol = 3, dimnames = list(NULL, c("x", "y", "z")))
p <- plot3d(x, type = "s")
str(p)
if (interactive() || in_pkgdown_example())
print(p, rglwidget = TRUE)
}
rgl/man/shadow3d.Rd 0000644 0001762 0000144 00000004261 14100762641 013620 0 ustar ligges users \name{shadow3d}
\alias{shadow3d}
\title{
Project shadows of mesh onto object.
}
\description{
Project a mesh onto a surface in a scene so that it appears to cast a shadow onto the surface.
}
\usage{
shadow3d(obj, mesh, plot = TRUE, up = c(0, 0, 1),
P = projectDown(up), outside = FALSE,
...)
}
\arguments{
\item{obj}{
The target object which will show the shadow.
}
\item{mesh}{
The mesh which will cast the shadow.
}
\item{plot}{
Whether to plot the result.
}
\item{up}{
Which direction is \dQuote{up}?
}
\item{P}{
The projection to use for draping, a 4x4 matrix. See \code{\link{drape3d}} for details on how \code{P} is used.
}
\item{outside}{
Should the function compute and (possibly) plot the region
outside of the shadow?
}
\item{\dots}{
Other arguments to pass to \code{\link{filledContour3d}},
which will do the boundary calculations and plotting.
}
}
\details{
\code{shadow3d} internally constructs a function that
is zero on the boundary of the shadow and positive inside,
then draws filled contours of that function. Because the
function is nonlinear, the boundaries will be approximate,
with the best approximation resulting from a large
value of \code{\link{filledContour3d}} parameter \code{minVertices}.
If \code{outside = TRUE}, the first color used by
\code{\link{filledContour3d}} will indicate the inside
of the shadow, and the second color will indicate the exterior.
}
\value{
The returned value from \code{\link{filledContour3d}}.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{drape3d}}, \code{\link{facing3d}}
}
\examples{
open3d()
obj <- translate3d(scale3d(oh3d(), 0.3, 0.3, 0.3), 0,0,2)
shade3d(obj, col = "red")
target <- icosahedron3d()
# We offset the target using polygon_offset = 1 so that the
# shadow on its surface will appear clearly.
shade3d(target, col = "white", polygon_offset = 1)
# minVertices = 1000 leaves noticeable artifacts on the edges
# of the shadow. A larger value gives a better result, but is
# slower.
# We use facing3d(target) so the shadow and outside part only
# appear on the upper side of the target
shadow3d(facing3d(target), obj, minVertices = 1000, plot=TRUE,
col = c("yellow", "blue"), outside = TRUE)
}
rgl/man/par3dinterpControl.Rd 0000644 0001762 0000144 00000002747 14100762640 015706 0 ustar ligges users \name{par3dinterpControl}
\alias{par3dinterpControl}
\title{
Control RGL widget like par3dinterp()
}
\description{
This control works with \code{\link{playwidget}} to
change settings in a WebGL display in the same way
as \code{\link{par3dinterp}} does within R.
}
\usage{
par3dinterpControl(fn, from, to, steps, subscene = NULL, omitConstant = TRUE, ...)
}
\arguments{
\item{fn}{A function returned from \code{\link{par3dinterp}}.}
\item{from, to, steps}{Values where \code{fn} should be evaluated.}
\item{subscene}{Which subscene's properties should be modified?}
\item{omitConstant}{If \code{TRUE}, do not set values that are
constant across the range.}
\item{...}{Additional parameters which will be passed
to \code{\link{propertyControl}}.}
}
\details{
\code{par3dinterpSetter} sets parameters corresponding to values produced by the result of
\code{par3dinterp}.
}
\value{
Returns controller data in a list of class "rglControl".
}
\author{
Duncan Murdoch
}
\examples{
example(plot3d)
M <- r3dDefaults$userMatrix
fn <- par3dinterp(times = (0:2)*0.75, userMatrix = list(M,
rotate3d(M, pi/2, 1, 0, 0),
rotate3d(M, pi/2, 0, 1, 0)),
scale = c(0.5, 1, 2))
control <- par3dinterpControl(fn, 0, 3, steps = 15)
control
if (interactive() || in_pkgdown_example())
rglwidget(width = 500, height = 250) \%>\%
playwidget(control,
step = 0.01, loop = TRUE, rate = 0.5)
}
rgl/man/rglToLattice.Rd 0000644 0001762 0000144 00000003534 14100762641 014503 0 ustar ligges users \name{rglToLattice}
\alias{rglToLattice}
\alias{rglToBase}
\title{
Convert RGL userMatrix to lattice or base angles
}
\description{
These functions take a user orientation matrix
from an RGL scene and approximate the
parameters to either \pkg{lattice} or base
graphics functions.
}
\usage{
rglToLattice(rotm = par3d("userMatrix"))
rglToBase(rotm = par3d("userMatrix"))
}
\arguments{
\item{rotm}{
A matrix in homogeneous coordinates to convert.
}
}
\details{
The \pkg{lattice} package can use Euler angles in
the ZYX scheme to describe the rotation of a scene
in its \code{\link[lattice:cloud]{wireframe}} or
\code{\link[lattice]{cloud}} functions. The
\code{rglToLattice} function computes these angles
based on \code{rotm}, which defaults to the current
user matrix. This allows RGL to be used
to interactively find a decent viewpoint and
then reproduce it in \pkg{lattice}.
The base graphics \code{\link{persp}} function does
not use full Euler angles; it
uses a viewpoint angle, and assume the z axis
remains vertical. The \code{rglToBase} function
computes the viewpoint angle accurately if the
RGL scene is displayed with a vertical
z axis, and does an approximation otherwise.
}
\value{
\code{rglToLattice} returns a list suitable to
be used as the \code{screen} argument to
\code{\link[lattice:cloud]{wireframe}}.
\code{rglToBase} returns a list containing
\code{theta} and \code{phi} components which
can be used as corresponding arguments in \code{\link{persp}}.
}
\author{
Duncan Murdoch
}
\examples{
persp3d(volcano, col = "green")
if ((hasorientlib <- requireNamespace("orientlib", quietly = TRUE)) &&
requireNamespace("lattice", quietly = TRUE))
lattice::wireframe(volcano, screen = rglToLattice())
if (hasorientlib) {
angles <- rglToBase()
persp(volcano, col = "green", border = NA, shade = 0.5,
theta = angles$theta, phi = angles$phi)
}
}
rgl/man/rglExtrafonts.Rd 0000644 0001762 0000144 00000004753 14100762641 014754 0 ustar ligges users \name{rglExtrafonts}
\alias{rglExtrafonts}
\title{
Register extra fonts
}
\description{
This function uses the \href{https://github.com/wch/extrafont}{\pkg{extrafont}}
package to help register system fonts for use with
FreeType in \pkg{rgl}.
}
\usage{
rglExtrafonts(..., quiet = TRUE)
}
\arguments{
\item{\dots}{
Vectors of fonts to try. See the Details.
}
\item{quiet}{
Whether to print information on progress.
}
}
\details{
The \pkg{extrafont}
package collects information on
installed fonts from the system. When you first
install \pkg{extrafont}, or after new fonts have been installed on your
system, run \code{extrafont::font_import()} to build
its database of system fonts.
Fonts can be installed in \pkg{rgl} using
\code{rglExtrafonts(rglname = familyname)} or \code{rglExtrafonts(familyname)}. In this call
\code{familyname} is a vector of family names to look
for in the \pkg{extrafont} database using \code{extrafont::choose_font(familyname)}; the first one found
will be registered with \pkg{rgl}. The optional name \code{rglname} will also be usable to refer to the font family.
If none of the given family names is found, no change
will be made to the registered fonts in \pkg{rgl}.
During startup, \pkg{rgl} detects whether \pkg{extrafont}
is installed, and if so runs
\verb{
rglExtrafonts(sans = c("Helvetica", "Arial"),
serif = c("Times", "Times New Roman"),
mono = c("Courier", "Courier New"))
}
to attempt to set up the default fonts.
Fonts found by \pkg{extrafont} can also be used in
some other graphics devices besides \pkg{rgl}; see
\href{https://github.com/wch/extrafont}{the \pkg{extrafont} documentation}
for details.
}
\note{
Each font in a display needs a unique \pkg{rgl} name;
if the associated font for a given name is changed,
all previously plotted text will also change.
Currently \code{\link{rglwidget}} displays will not
respect the new definitions.
}
\value{
Invisibly returns a vector giving the \pkg{rgl} name
and the family name for the newly installed font.
}
\author{
Duncan Murdoch
}
\seealso{
\code{\link{text3d}}, \code{\link{rglFonts}}
}
\examples{
if (requireNamespace("extrafont") && !in_pkgdown_example()) {
open3d()
text3d(1,1,1, "Default", family = "sans", cex = 2)
# Attempt to register new sans-serif font:
newfamily <- rglExtrafonts(newsans = c("Comic Sans MS", "Impact",
"Verdana", "Tahoma"))
text3d(2,2,2, newfamily, family = "newsans", cex = 2)
}
}
rgl/man/asRow.Rd 0000644 0001762 0000144 00000004607 14137472630 013211 0 ustar ligges users \name{asRow}
\alias{asRow}
\alias{getWidgetId}
\title{
Convenience functions for RGL HTML layouts
}
\description{
The \code{asRow} function arranges objects in a row in the display;
the \code{getWidgetId} function extracts the HTML element ID
from an HTML widget.
}
\usage{
asRow(..., last = NA, height = NULL, colsize = 1)
getWidgetId(widget)
}
\arguments{
\item{\dots}{
Either a single \code{"combineWidgets"} object produced by
\code{asRow} or a \code{\%>\%} pipe of RGL objects,
or several objects intended for rearrangement.
}
\item{last}{
If not \code{NA}, the number of objects from \code{...} that
are to be arranged in a row. Earlier ones will remain in a column.
}
\item{height}{
An optional height for the resulting row. This is normally specified
in pixels, but will be rescaled as necessary to fit the display.
}
\item{colsize}{
A vector of relative widths for the columns in the row.
}
\item{widget}{
A single HTML widget from which to extract the HTML element ID.
}
}
\details{
Using \code{asRow} requires that the \pkg{manipulateWidget}
package is installed.
\code{asRow} produces a \code{"combineWidgets"} object which
is a single column whose last element is another \code{"combineWidgets"} object which is a single row.
If \code{n} objects are given as input and \code{last} is given a value
less than \code{n}, the first \code{n - last} objects will be displayed
in a column above the row containing the \code{last} objects.
}
\value{
\code{asRow} returns a single \code{"combineWidgets"} object suitable for display or nesting
within a more complicated display.
\code{getWidgetId} returns a character string containing the
HTML element ID of the widget.
}
\author{
Duncan Murdoch
}
\seealso{
\link{pipe} for the \code{\%>\%} operator.
}
\examples{
if (requireNamespace("manipulateWidget", quietly = TRUE) &&
require("crosstalk", quietly = TRUE)) {
sd <- SharedData$new(mtcars)
ids <- plot3d(sd$origData(), col = mtcars$cyl, type = "s")
# Copy the key and group from existing shared data
rglsd <- rglShared(ids["data"], key = sd$key(), group = sd$groupName())
w <- rglwidget(shared = rglsd) \%>\%
asRow("Mouse mode: ", rglMouse(getWidgetId(.)),
"Subset: ", filter_checkbox("cylinderselector",
"Cylinders", sd, ~ cyl, inline = TRUE),
last = 4, colsize = c(1,2,1,2), height = 60)
if (interactive() || in_pkgdown_example())
w
}
}
rgl/man/spheres.Rd 0000644 0001762 0000144 00000004617 14100762641 013562 0 ustar ligges users \name{spheres3d}
\alias{spheres3d}
\title{Add spheres}
\description{
Adds a sphere set shape node to the scene
}
\usage{
spheres3d(x, y = NULL, z = NULL, radius = 1, fastTransparency = TRUE, ...)
}
\arguments{
\item{x, y, z}{Numeric vector of point coordinates corresponding to
the center of each sphere. Any reasonable way of defining the
coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}}
for details.}
\item{radius}{Vector or single value defining the sphere radius/radii}
\item{fastTransparency}{logical value indicating whether
fast sorting should be used for transparency. See the Details.}
\item{ ... }{Material properties. See \code{\link{material3d}} for details.}
}
\details{
If a non-isometric aspect ratio is chosen, these functions will still draw
objects that appear to the viewer to be spheres. Use \code{\link{ellipse3d}}
to draw shapes that are spherical in the data scale.
When the scale is not isometric, the radius is measured in an average scale.
In this case the bounding box calculation is iterative, since rescaling the
plot changes the shape of the spheres in user-coordinates, which changes
the bounding box. Versions of \pkg{rgl} prior to 0.92.802 did not do
this iterative adjustment.
If any coordinate or radius is \code{NA}, the sphere is not plotted.
If a texture is used, its bitmap is wrapped around the
sphere, with the top edge at the maximum y coordinate,
and the left-right edges joined at the maximum in the
z coordinate, centred in x.
If the \code{alpha} material value of the spheres is less than
the default \code{1}, they need to be drawn in order from
back to front. When \code{fastTransparency} is \code{TRUE}, this is approximated by sorting the centers and drawing
complete spheres in that order. This produces acceptable
results in most cases, but artifacts may be visible,
especially if the \code{radius} values vary, or they
intersect other transparent objects. Setting
\code{fastTransparency = FALSE} will cause the sorting
to apply to each of the 480 facets of individual spheres.
This is much slower, but may produce better
output.
}
\value{
A shape ID of the spheres object is returned.
}
\examples{
open3d()
spheres3d(rnorm(10), rnorm(10), rnorm(10),
radius = runif(10), color = rainbow(10))
}
\seealso{
\code{\link{material3d}}, \code{\link{aspect3d}} for setting non-isometric scales
}
\keyword{dynamic}
rgl/man/figures/ 0000755 0001762 0000144 00000000000 14146446052 013263 5 ustar ligges users rgl/man/figures/READMEpolyhedra-1-rgl.png 0000644 0001762 0000144 00000023207 14146473075 017567 0 ustar ligges users ‰PNG
IHDR ×ÙÙA sRGB ®Îé IDATxœí{UÕï¿û`äa]щ¢ÈCåq0ªî̼œš D ‹Ö‰Ä‰‚øˆ¹×njtnÝI$&‘©äÎ#%êäLŒÑ˜Ð$£Í#ˆhb›`Cf®b¥níùãô>g?ÖÚ{ýZûñýP›>g?×ÞÍéþðûõ[–mÛ6!„Bɉ†éB!„zA%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹B%„B!¹rŠéB!qغ{úwo3ÝŒB±üSŸ3Ý„Â0xt;öíycϺ
pá”[
·ˆ¸¡€B)_þǯbõ?|Õt3
G×å³0ûòY¦›Q¶cp`ZÿIÙ·çk €±gÍ¢” ˶mÛt#!„Æÿ÷ ¦›PXžøâ?QBì{ùá¶tFA)ÍŸÚ÷íßÒO,X„s¬óðàªÕ¦›C!$‚OÞõ¦›PhVÿ##úlþ=_þ=_Ãs&â¹
±só
-‰}ùaÓÍ«$µ€öoéÇ—zWã…¾þÀ¶•½+pGÏ
"EbÕê5èYñYÓÍ „¸`ê]‹?Wûþ :PU)MÚ h˜xúYÙ»sš]èšß•CËHQXµz
zìü·÷Ž[)¢„ ʧuOÅïÜ|C»ÿg–8R:ö¬«0öÌ«2¿^U¨€êˆ§Šh=ØÒ¿Í…7H·SD 1û}êóëg^7Ýcä% "(¥ÑT^@“ˆ§Šh5‰O?Ñz³êÙï£çÿÄt3jÇ'ïúô¿È’Kºt]1ÿí?™n†žÛ0Ñt<\8õ¯ €R:De4Mñô³²·Õ?”ýDËÍ–þè]ý0ú^ØëxŠhýX°öaôí}
Í‹.Ææ[Øÿ+/˜zOF]ûƒM@EÔYJ+' YЧŸ9Í.ÌivQDKFRñtC Ž|:PBóaëîmXt'G½'¥ŽýAË "ê"¥•Ð<ÅÓE´<,Xôieñ|ÿ9âÃû”ö¥ˆV¿|:PB³‡ý>Ó£nýAË* "ª(¥¥P“â)‚%œŠ‰–xž{þËŒÿÖЃß]§|Šhõɧ%4;˜zO—ºõ’€Š(»”–V@ÓÏá“x7•sÑ¢à/©Å™3ÿgÎü£Àú£;€£; |Šh5ˆ’OJhúP>³¡NýA«. ")-CÒÒ hZâ9#0g´_÷¿Þ‡® M Àq¼íùšŠ¨tG¶À¯¹ï?çBéöwïÃþMkµÎI-/ªòé@ M¦Þ³£ýAnÇÎ-6ÝŒBPT)-€&Ïá ƒ3Ú¯Ýtß¶Ko[‚o|å[Xÿ•o¶§!¤Ñ|ˆ3Àèç^„^s‹òþ?}?}V«]Ñr¡+Ÿ”Ðt |fKRñÐpŠ ¥…Ð8â9#GŽ›€i·>„‘çM€Õh Ñh a5а,4,–ÂÒh/ãFgÏú“ÖyÇ©÷[ë{a;,útœÛ&¶|@ßÞ×°`^dž´°Ø¶
Û¶[‘?Û»ÎYo£¥\þõíý…Ûlg—Àvÿß"X5t§}Á%xŽeH ãdÛ!ÚÞÞæ_/Ø?çï')Ž|.¼þîL¯c<Ú¿¥Þ\Ô~Ÿ$®C÷K°4D4¿±ú[Xÿ`p@RZÈ"¤Œˆªa›¤µÿ9³>Œ³g}8VCÀ‘mOãð¶§õŽ;ô‹lD”ÈB>Ý0ªÎ«ïìÃßhÕÝ•E0Ã×CšnWMß‹b¬©üà°/¢E0*.KËK£¡Þõë'ÿ﨔–›oÀàÀ6ÓÍ(Ž|È4ú PG<óÎÀõ÷EîÓuN3‡–´ð÷#¥ˆŠÑ-¯túyãœÙÁé*ÑI+ðÂ…íù†
`×WþJCô=ù÷œd€¬åÓªN÷Ëwµ^(¦ÛÃÄS5Õ¸R]F]évï«ð}Åéw]mY?åoUZZJ( ú¸åÈ^@sOÁÿlËÏ1Ýš…eÍÛÛétYy¤¬è^¹¤õ&byä;åÖ&§_«ÓÕàÉÞM˜d]Žo¬Ê.
[6tåóÜÙÁÄ…·aÔyÓé
«“†÷¤ã®4»/åny÷·ÖyiúÿzûÃ8wöG”ÛÚ\x¶ôïˆóXHLò’O€éx:éìð”z;¥íÛ_5ÕîΡ{Séiò´'Ý'åyšÞ—š¥Ùô;ljRðLÃ7»^zÇ#ŸY§ßº¾÷[¹G;ý,½sH@ý?Û‹LŸ;
3æN3ÖÎ18ý}[]¿H¬Z½FK>/]t;Æu}T.C¢©Òï3¼?¨\FÇu}—.R¯¨Ð\xV^çñMò”OJ¨jâUá6IÐÀ>š}Aã,Ñ2êIHD3¸XD}Û$"ZeýTg×Kï`×KïxÖMž:7óëæ. '0˜÷%=<ò/uä3,:´½ûÎä’’æô eE§ÌÒ¨ñ—àª`ÔøK\â© CrˆŠz¢âˆ§PF‡Ö;í×õQ¥ö÷>ø0%4cLȧ%TW:Y.žaR©(ʲéÆX|ÎH)ÕQáviäÓîD>+. D
‘|ùè)™_ÁÇIœÌû’mºïZ‚éó4"š0}^+
ºëùde™âbòyùœ|í
œ~ÞÅí÷–¬ößPé%n^²¾dí_•¶oß¡k;Q†óæ|–eá7/|7òZÎý²Vhú˜”OGBÙ'TL;•o¿OÿgÍÙf[®#ýŸÃíÞý:ïìÀÛó%UÚ–¨x‰¡ý¥û…m:–Ô™|æ‘~D@»š³ñž!©Zz· ï§$ýî^Ölʯ/¨›DWs¶‘k‹>$Ÿ£Æ_‚Ù+mG=ÛQK_„³¡š~o…4|C!u·å¼9Ãì•â¼9‹¼§Þf™¦”)‚|:0*çÒ\osGIeÛýÑÎ~Ñ‘QÕÔ|ì~ ÎE<LÈ£¢œÃ·íÒèÏ GªÃS?(¡AüÂÁŒ’Vá~BÙÔL¡«F5ä2=•œ3°¯_6Åûø·_:’)øº±þÛ¿
•ϼÉ]@ç4» äÝ›1oZ¼è§`ÿéó¦a†Î &¢Œ§ÆçhbÄhàô³€±ã[ËÈ3‘gâÄÑ#t»_<…ÒHµ«OÁ)Ž~ZA)ɨ_D}iùo¿
Õº?ç^O?«uÿ#F·Ÿk…êQùtèÛû¬•·™nF!˜èô
¥‚p
÷‘ì§õ„Y…yëM‚0ª‚°B.‘ª²)Ú'¸]óCJËáßcý·«´ïÂëîʸ5ŒE@óJïyê!}é‘ÑîÏ瓊wÝö*³¥š7®ˆ&†N9-°ÿ‰7ßh‹c@òü©wY4¬¨VT!ÒÆ†%‹Êiû>ªó\ÆŽG󯕨²cwÆß‘òc¼4òé†ÚÂ/”zÂéß'Ù
fàÚ>Y
‘Ö¸©øàE%r*”j
©{E`
ÞÁ?»Qy¦ßƒ
dŸ†ïþ¼Fê]QR§_=
3®Î6
jªJ€1N9M(šaüîÈPñŒŒ€Šú€6:b\‚£áÃú€
# ‚÷wFO xV$”²K\ÙÛŸœ¤Â)“MÈå4B,ƒQQýEMTE’‰H)íì«.¤Õ×P¢#Ÿ&0* Y§á—Þ›NßÏ@Y¦ïeÛ”Åç£9°}spä»`ð‘?åýÔœŠÓ
¤äeƒ‘\²zâЦe¥¨Š¼Uå>â0iä„È(€À>Jû D3, ~jFò>
‚úÖ¹û€:²:xh.Ï«TMÚªv?ªØ@¬¨l?YÐà1jÑÐÔYÔÓÓ0‰œÆ•R÷>I¾I¤ÐÈ
̇‘wú0²K7K£Ÿ¬‹!¦y¤âI8Çß|Ã+šH§(ú)Š|ªF
>òJ¦H<½QOgûþí?2ý+CUeª÷Eò¨lß œÊS쮃ҽ)áõÄ‚*h‚LL5# U¦Î}@ãȧ)ŒhQÐîŒRïþ¥eM‘:–_ŠËþm?ЧgÆ£ix%*ýî•Ñ ˆZ²HD‹ªKZÕïÏϤ‘RH·GˆihÔ
M+"êù‘¢KÏ+ˆ©Š”2_=’ÈgÞéw šn´ûÞ%XúAúÝùªãú:ýCéGAëZ|>oÿzoPxz"¾ùßå)ø°ñá#ße¢é—͆oûޔϤÔMÊêv¿ªÑÏÀ¾Pï±’(hÜHhà‚×FF@e³Fi÷:5»QyM½éǸ€éõíväG?ý’)#b’;
š–„2ý®Ïë/ü 0úÝ/â|D´3bø°¾Ÿ~Ùô·ËjX°"ÿ’0ê*cu¹oõCÑÑOïþ # º'´Ú„PÏ¥uö'Õ ©|fÒï@A4´óÒ°‘ïîõþmaQP…ó-M©/hÚÝêÀ±ƒ¯·DS&¡
IäSUDuÅSr}oT´_=ÿŒéGWZê"a2êrÿiRø÷ÕŒ~¯'‰€êFA…6nÞãBû’R“†|šÄˆ€úg÷I#
ßíN½j¯Ýïeâ©x¾G¾Ÿ¼,“ÿ9Ôa$‡æ•WÄ>vð7û"%´2^µ“"žÎva$Ô'Ÿ¯%Ï$Ï©
ÔE¾¢¨üsP‘L…ȧ÷qô3³¾Ÿá
‰Ž„FEA