[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