[R] rgl how to plot a cylinder like arrow3d?

Duncan Murdoch murdoch.duncan at gmail.com
Tue Aug 9 12:28:35 CEST 2011


On 11-08-09 5:22 AM, René Mayer wrote:
> Dear List,
> I'm trying to draw vector in XYZ with rgl under use of a cylinder3d.
> Therefore I scale and rotate a basis-cylinder).
> However, somehow the rotation is wrong as
> verified by overplotting arrow3d().
> Where is my mistake?

I would guess it is in assuming that theta can be computed on the 
original vector, not on the rotated one:  rotating about the Y axis 
changes end[1].

I usually use a Gram-Schmidt type calculation to do this sort of thing. 
  The undocumented rgl:::GramSchmidt function does this for 3x3 
matrices, orthogonalizing by row.  So you could replace all 3 of your 
rotations (including the first one) by this:

rotation <- 
rgl:::GramSchmidt(end-start+c(1,0,0),end-start+c(0,1,0),end-start, 
order=c(3,1,2))
c <- rotate3d(c, matrix=rotation)

(I notice you also forgot to translate the cylinders to start; this 
doesn't matter in your example, but would if you had a non-zero origin.)

One problem with this kind of display is that it assumes the coordinates 
are all of equal range.  If you try plotting one of these vectors when 
the range of x, y and z are drastically different, the cylinders will 
look really strange.

Duncan Murdoch

>
> library(heplots)
> library(rgl)
>
> # ... 2 vectors
> data=data.frame(row.names=c('X','Y','Z'), x1=c(2,1,5),y=c(4,3,2))
>
> vector3D=function(start=c(0,0,0), end, mycol='green'){
> # ... cylinder as basis-vector
> c=cylinder3d(rbind(      c(start), # start
> 			 c(0,0,1)), # end
> 		         radius = 0.2,
>                            e1=cbind(0, 0, 1),
>                            e2=cbind(1, 0, 0),
> 		         sides=10
>                      )
>
> # ... rotate cylinder horizontally and scale it
> len=sqrt(sum(abs(end)*abs(end)))
> c=scale3d(c,0.1,0.1,len)
> c=rotate3d(c,-(pi/2),0,1,0)
>
> # ... rotation angles
> theta = atan2(end[2],end[1]) # angle in yx-plane for Z-achses rotation
> phi = atan2(end[3],sqrt(end[1]^2+end[1]^2)) # angle in zx for Y-achses
> rotation
>
> # ... rotation
> c=rotate3d(c,phi,0,1,0) # Y-achses rotation
> c=rotate3d(c, -theta,0,0,1) # Z-achses rotation
> shade3d(addNormals(c), col=mycol)
> }
>
> open3d()
> vector3D(start=c(0,0,0),end=data[,1], 'red');
> vector3D(start=c(0,0,0),end=data[,2],'green')
> arrow3d(c(0,0,0),data[,1],color='red');arrow3d(c(0,0,0),data[,2],
> color='green')
> axes3d(c('x','y','z'));title3d('main','sub','X','Y','Z');box3d()
>
> thanks,
> René
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.



More information about the R-help mailing list