Michael Friendly
2012-Mar-09 19:36 UTC
[R] rgl: cylinder3d() with elliptical cross-section
For a paper dealing with generalized ellipsoids, I want to illustrate in 3D an ellipsoid that is unbounded in one dimension, having the shape of an infinite cylinder along, say, z, but whose cross-section in (x,y) is an ellipse, say, given by the 2x2 matrix cov(x,y). I've looked at rgl:::cylinder3d, but don't see any way to make it accomplish this. Does anyone have any ideas? thx, -Michael -- Michael Friendly Email: friendly AT yorku DOT ca Professor, Psychology Dept. York University Voice: 416 736-5115 x66249 Fax: 416 736-5814 4700 Keele Street Web: http://www.datavis.ca Toronto, ONT M3J 1P3 CANADA
Michael Friendly <friendly <at> yorku.ca> writes:> > For a paper dealing with generalized ellipsoids, I want to illustrate in > 3D an ellipsoid that is unbounded > in one dimension, having the shape of an infinite cylinder along, say, > z, but whose cross-section in (x,y) > is an ellipse, say, given by the 2x2 matrix cov(x,y). > > I've looked at rgl:::cylinder3d, but don't see any way to make it > accomplish this. Does anyone have > any ideas? >I haven't quite got this in the form you want, but maybe it's a start (I started from the ellipsoid3d() function in demo("shapes3d") ... cyl3d <- function(rx=1,ry=1,n=30,ctr=c(0,0,0), zmax=1, qmesh=FALSE, trans = par3d("userMatrix"),...) { if (missing(trans) && !rgl.cur()) trans <- diag(4) degvec <- seq(0,2*pi,length=n) zvec <- seq(0,zmax,length=n) ecoord2 <- function(p) { c(rx*cos(p[1]),ry*sin(p[1]),p[2]) } v <- apply(expand.grid(degvec,zvec),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=...),matrix=trans)) } cyl3d(rx=1,ry=2,zmax=5,col="blue") cyl3d(rx=3,ry=2,zmax=5,col="red",alpha=0.3,ctr=c(2,1,0), trans=rotationMatrix(pi/6,0,0,1))
My first reply to this went privately, by accident. I've done a little editing to it, but mainly this is for the archives. On 12-03-09 2:36 PM, Michael Friendly wrote:> For a paper dealing with generalized ellipsoids, I want to illustrate in > 3D an ellipsoid that is unbounded > in one dimension, having the shape of an infinite cylinder along, say, > z, but whose cross-section in (x,y) > is an ellipse, say, given by the 2x2 matrix cov(x,y). > > I've looked at rgl:::cylinder3d, but don't see any way to make it > accomplish this. Does anyone have > any ideas?rgl has no way to display curved surfaces that are unbounded. (It has lines and planes that adapt to the viewport.) So you would need to make a finite cylinder, and it will be up to you to choose how big to make it. The cylinder3d() function can do that, but it's not very good at cylinders that are straight. (This is a little embarrassing...) It sets up a local coordinate system based on the curvature, but if there are no curves, it fails, and you have to supply your own coordinates. So here's how I would do what you want: center <- cbind(0, 0, 1:10) # cylinder centered on points (0, 0, z) e2 <- cbind(1, 0, rep(0, 10)) # define the normal vectors cyl <- cylinder3d(center, e2=e2) # Now you have an octagonal cylinder. Use the sides arg to cylinder3d # if it doesn't end up smooth enough, but in most cases I've seen, 8 # is sufficient. # Define a transformation to the x and y coordinates to give the # elliptical shape; use it as the # top left 2x2 matrix of a 3x3 matrix xfrm <- matrix( c(2, 1, 0, 1, 3, 0, 0, 0, 1), 3,3, byrow=TRUE) cyl <- transform3d(cyl, xfrm) cyl <- addNormals(cyl) # this makes it shade smoothly shade3d(cyl, col="green") decorate3d() # show some axes for scale Duncan Murdoch