Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

replicating an rgl viewpoint in lattice

Tags:

r

lattice

rgl

It would be convenient to interactively select a decent viewpoint using rgl and then adopt the same orientation in a lattice 3d-plot. For example, given the following plot using a non-informative viewpoint.

library(lattice)
wireframe(volcano, screen = list(x=0, y=0, z=0))

enter image description here

The same can be opened in rgl by

library(rgl)
persp3d(volcano)
view3d(0, 0)

enter image description here

Interactively it is easy to rotate the plot to an informative view.

enter image description here

The matrix giving the current rgl viewpoint in can be extracted by

p <- par3d()
p$userMatrix

How can this matrix be converted into corresponding x,y,z screen parameters to replicate the view in lattice?

UPDATE 1

I tried out 42's conversion below. The code shows the rgl plot and the corresponding lattice plot per row. If I implemented it correctly (see code below), there appears to still be an issue.

enter image description here

# convert rgl viewpoint into lattice 
# screen orientation
rgl_to_lattice_viewpoint <- function()
{
  p <- par3d()
  rotm <- p$userMatrix
  B = 360*atan(rotm[1,2]/rotm[2,2])/(2*pi)
  P = 360*asin(-rotm[3,2])/(2*pi)
  H = 360*atan(rotm[3,1]/rotm[3,3])/(2*pi)
  list(x=-B, y=-P, z=-H)
}


# read and plot PNG image 
plot_png <- function(f)
{
  img <- readPNG(f)
  rimg <- as.raster(img)      # raster multilayer object
  plot(NULL, xlim=c(0,1), ylim=c(0,1), xlab = "", ylab = "", 
       asp=1, frame=F, xaxt="n", yaxt="n")
  rasterImage(rimg, 0, 0, 1, 1) 
}


# create rgl snapshot with random rotation and 
# corresponding lattice wireframe plot
lattice_plus_rgl_plot <- function()
{
  # rgl plot random rotation
  persp3d(volcano, col = "green3")
  theta <- sample(-180:180, 1)
  phi <- sample(-90:90, 1)
  view3d(theta, phi, fov=40)
  v <- rgl_to_lattice_viewpoint()
  f <- tempfile(fileext = ".png")
  rgl.snapshot(f)
  rgl.close()

  # lattice plot
  f2 <- tempfile(fileext = ".png")
  png(f2)
    print(wireframe(volcano, screen = v))
  dev.off()

  # plot both
  plot_png(f)  
  plot_png(f2)  
}

# CREATE SOME PLOTS 

library(rgl)
library(lattice)
library(png)
par(mfrow=c(3,2), mar=c(0,0,0,0))
replicate(3, lattice_plus_rgl_plot())
like image 953
Mark Heckmann Avatar asked Oct 30 '22 04:10

Mark Heckmann


1 Answers

I used the answer to this question for conversion from a rotation matrix to angles: Conversion euler to matrix and matrix to euler . I admit to concern that I see another somewhat different answer here: How to calculate the angle from Roational matrix . (My linear algebra is not good enough to determine which of these is correct.)

p <- par3d()
rotm <- p$userMatrix
B = 360*atan(rotm[1,2]/rotm[2,2])/(2*pi)
P = 360*asin(-rotm[3,2])/(2*pi)
H = 360*atan(rotm[3,1]/rotm[3,3])/(2*pi)

> print(list(B,P,H))
[[1]]
[1] 41.54071

[[2]]
[1] 40.28412

[[3]]
[1] 41.24902

At that point I had already rotated the RGL-object to roughly the "viewing point" that you had suggested. I discovered by experimentation that the negative values supplied to the wireframe call delivered apparently correct results. "Viewer rotation angles" are plausibly seen as the negative for "object rotation angles".

 png(); print(wireframe(volcano, screen = list(x=-B, y=-P, z=-H)) ); dev.off()

enter image description here

There is a rotate.wireframe function in the TeachingDemos package but it does not play well with concurrently running rgl plots. (No plot was apparent until I closed the rgl device.) It also seemed kind of buggy when running on a Mac (thick black line across the lattice plot). It uses the X11/XQuartz facilities to manage interaction via tk/tcl functions and I was unable to reproduce the plots from the angles being displayed. Looking at the code I'm not able to understand why that should be so. But your mileage may vary.

like image 111
IRTFM Avatar answered Nov 09 '22 14:11

IRTFM