(Ted Harding) wrote:
> On 19-Sep-05 Robin Hankin wrote:
> 
>>Hi
>>
>>the manpage for persp() has a wonderful section where a the
>>trans3d()  function is used with points() and lines() to add
>>red dots and a green sinusoid to the Mexican hat surface.
>>
>>Does anyone have a way to tell what distance  a point is from
>>the eye/camera?
>>
>>Take the following line:
>>
>>lines (trans3d(x, y=10, z= 6 + sin(x), pm = res), col = 3)
>>
>>Is there a function like trans3d() that returns a vector of
>>distances from the x,y,z point to the camera?  I want this so
>>I can plot clouds of points with the further ones in smaller
>>plotsizes, and perhaps even fading to white (as though viewed
>>through fog).
> 
> 
> Wonderfully put! That's what statistics is about!
> 
> I think you may have to write your own. This is possible given
> the values for the parameters xlim, ylim, zlim, r, theta, phi
> (default as defined in ?persp, or explicitly user-defined),
> since you can then determine the 3D coordinates of the "Eye"
> relative to the (X,Y,Z) axes being plotted, after which the
> distance to a particular (x,y,z) point is trivial.
> 
> E.g.
> 
> 1. Coordinates of Eye relative to the centre of the box
> 
>    xE <- r*sin(theta + pi)*cos(phi)
>    yE <- r*cos(theta + pi)*cos(phi)
>    zE <- r*sin(phi)
> 
> 2. Centre of box relative to real (0,0,0)
> 
>    xC <- mean(xlim); yC <-mean(ylim); xC <- mean(zlim)
> 
> 3. Coordinates of (x,y,z) relative to Eye
> 
>    x1 <- x - xE - xC; y1 <- y - yE - yC; z1 <- z - zE - zC
> 
> 4. Distance from Eye to (x,y,z)
> 
>    d = sqrt(x1^2 + y1^2 + z1^2)
> 
> (Hoping I've not got anything the wrong way round there!)
> 

I think you forgot the rescaling to [0,1], but it's probably even easier 
than that.  persp returns the 4x4 transformation matrix used to take 
user coordinates into screen coordinates.  trans3d uses that matrix to 
extract the screen x and screen y coordinates (extend the 3-vector to 
homogeneous coordinates by appending a 1, multiply by the projection 
matrix, convert back to Euclidean coordinates by dividing by the last 
coordinate).  You can probably just do what trans3d does, but keep the 
z-coordinate, to get a reasonable measure of depth.  i.e.

depth3d <- function(x,y,z, pmat) {
   tr <- cbind(x, y, z, 1) %*% pmat
   return(tr[,3]/tr[,4])
}

This is sufficient for doing fog calculations.  For perspective 
shrinkage, you'll need to say where the user's eye is in these 
coordinates (or just use depths as distances).

Duncan Murdoch

______________________________________________
[email protected] mailing list
https://stat.ethz.ch/mailman/listinfo/r-help
PLEASE do read the posting guide! http://www.R-project.org/posting-guide.html

Reply via email to