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 ______________________________________________ R-help@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.