[R] adding 3D arrows to 3D plots

Barry Rowlingson b.rowlingson at lancaster.ac.uk
Sun Jan 10 19:55:15 CET 2010


Have a go with this:

arrow3d <- function(p0=c(0,1,0),p1=c(1,1,1),s=0.1,theta=pi/4,n=3,...){
 ##    p0: start point
 ##    p1: end point
 ##     s: length of barb as fraction of line length
 ## theta: opening angle of barbs
 ##     n: number of barbs
 ##   ...: args passed to lines3d for line styling

 require(geometry)
 require(rgl)

 ## rotational angles of barbs
 phi=seq(0,2*pi,len=n+1)[-1]

 ## length of line
 lp = sqrt(sum((p1-p0)^2))

 ## point down the line where the barb ends line up
 cpt=(1-(s*lp*cos(theta)))*(p1-p0)

 ## draw the main line
 line = lines3d(c(p0[1],p1[1]),c(p0[2],p1[2]),c(p0[3],p1[3]),...)

 ## need to find a right-angle to the line. So create a random point:
 rpt = jitter(c(
   runif(1,min(p0[1],p1[1]),max(p0[1],p1[1])),
   runif(1,min(p0[2],p1[2]),max(p0[2],p1[2])),
   runif(1,min(p0[3],p1[3]),max(p0[3],p1[3]))
   ))

 ## and if it's NOT on the line the cross-product gives us a vector
at right angles:
 r = extprod3d(p1-p0,rpt)
 ## normalise it:
 r = r / sqrt(sum(r^2))

 ## now compute the barb end points and draw:
 pts = list()
 for(i in 1:length(phi)){
   ptb=rotate3d(r,phi[i],(p1-p0)[1],(p1-p0)[2],(p1-p0)[3])
   lines3d(
           c(p1[1],cpt[1]+p0[1]+lp*s*sin(theta)*ptb[1]),
           c(p1[2],cpt[2]+p0[2]+lp*s*sin(theta)*ptb[2]),
           c(p1[3],cpt[3]+p0[3]+lp*s*sin(theta)*ptb[3]),
           ...
           )
 }
 return(line)
}

This creates a line with 'n' arrow barbs at one end, equally spaced
when you look at the line end-on. The barb length is 's' times the
length of the line, and the opening angle is theta. Just do arrow3d()
to get something.

Might be useful, plus I wanted to brush up on my vector geometry anyway...

Barry



More information about the R-help mailing list