function [x,y,z] = CreateUniformDotsIn3DFrustum(ndots,FOV,aspectr,depthrangen,depthrangef,eyeheight)
% [x,y,z] = CreateUniformDotsIn3DFrustum(ndots,FOV,aspectr,depthrangen,depthrangef,eyeheight)
%
% Sample dots in frustum uniformly, creating a cloud tightly fitting in the
% frustum. When the optional 6th parameter eyeheight is given, dots will be
% uniformly sampled on a ground plane at -eyeheight.
%
% z is not sampled from a uniform distribution, but from a parabolic
% distribution as the area of cross sections of the frustum is a quadratic
% function of the depth plane's depth ( (z*2*tan(FOV/2))^2 * aspectr )
%
% Here, I use Inverse transform sampling to transform a uniform random
% variable into the quadratic shape random variable
% see Luc Devroye. Non-Uniform Random Variate Generation. New York:
% Springer-Verlag, 1986. Chapter 2
% (http://cg.scs.carleton.ca/~luc/chapter_two.pdf)
% compile following in latex to see full derivation:
% ----
% \documentclass[12pt,a4paper]{minimal}
% \usepackage{amsmath}        % math
% 
% \begin{document}
% \textbf{Derivation}:\\
% Use pdf related to cross-section surface of frustum:
% \(\left(2 z \tan\left(\frac{FOV}{2}\right)\right)^2 aspectr\)\\
% \(z_1\) is the distance of the near depth plane\\
% \(z_2\) is the distance of the far depth plane\\
% \(y\) is a uniform random variable\\
% Given: \(F(z_2)=1\) and \(F(z_1)=0\).
% \begin{align}
%     F(z) &= \int\limits^z_{z_1} k z^2 \, \mathrm{d}z\\
%     F(z) &= \frac{k}{3} \left(z^3 - z_1^3\right)\\
%     k    &= \frac{3}{z_2^3-z_1^3}\\
%     F(z) &= \frac{z^3-z_1^3}{z_2^3-z_1^3}
% \end{align}
% Substitute \(y\) for \(F(z)\) and factor out \(z\):
% \begin{align}
%     z^3  &= y\left(z_2^3-z_1^3\right) + z_1^3\\
%     z    &= \sqrt[3]{y\left(z_2^3-z_1^3\right) + z_1^3}
% \end{align}\\
% For a ground plane, the width of the frustum at depth \(z\) is given by
% \(2 z \tan\left(\frac{FOV}{2}\right) aspectr\).\\
% By following the same inverse transform sampling steps, we would end up
% with 
% \[ z = \sqrt{y\left(z_2^2-z_1^2\right) + z_1^2} \]
% for the linear distribution between \(z_1\) and \(z_2\).
% 
% \end{document}
% ----

% 2008       DN  Wrote it.
% 2009-06-06 DN  Changed input check to allow for vector near and far
%                depthrange and allowed near and far depthrange to be
%                the same, to place dots at exactly that depth
% 2010-06-08 DN  Added support for uniform groundplanes

psychassert(all(depthrangen<=depthrangef),'Near clipping plane should be closer than far clipping plane');

u   = RandLim([1,ndots],0,1);                                           % get uniform random variable
if nargin>5
    % eye height specified, ground plane
    z   = -(u.*(depthrangef.^2-depthrangen.^2)+depthrangen.^2).^(1/2);      % transform to linear distribution (negate as depth postiion is a negative number
else
    % cloud
    z   = -(u.*(depthrangef.^3-depthrangen.^3)+depthrangen.^3).^(1/3);      % transform to parabolar distribution (negate as depth postiion is a negative number
end

yrs = -z*tand(FOV/2);
if nargin>5
    y   = -eyeheight*ones(1,ndots);
else
    y   = RandLim([1,ndots],-yrs,yrs);
end
xrs = yrs * aspectr;
x   = RandLim([1,ndots],-xrs,xrs);

% for a uniform sample over z:
% z   = -RandLim([1,ndots],depthrangen,depthrangef);
