function  model = autoTree( nb, bf, skew, taper )

% autoTree  Create System Models of Kinematic Trees
% autoTree(nb,bf,skew,taper)  creates system models of kinematic trees
% having revolute joints, mainly for the purpose of testing dynamics
% functions.  nb and bf specify the number of bodies in the tree, and the
% branching factor, respectively.  The latter is the average number of
% children of a nonterminal node, and must be >=1.  bf=1 produces an
% unbranched tree; bf=2 produces a binary tree; and non-integer values
% produce trees in which the number of children alternates between
% floor(bf) and ceil(bf) in such a way that the average is bf.  Trees are
% constructed (and numbered) breadth-first.  Link i is a thin-walled
% cylindrical tube of length l(i), radius l(i)/20, and mass m(i), lying
% between 0 and l(i) on the x axis of its local coordinate system.  The
% values of l(i) and m(i) are determined by the tapering coefficient:
% l(i)=taper^(i-1) and m(i)=taper^(3*(i-1)).  Thus, if taper=1 then
% m(i)=l(i)=1 for all i.  The inboard joint axis of link i lies on the
% local z axis, and its outboard axis passes through the point (l(i),0,0)
% and is rotated about the x axis by an angle of skew radians relative to
% the inboard axis.  If the link has more than one outboard joint then they
% all have the same axis.  If skew=0 then the mechanism is planar.  The
% final one, two or three arguments can be omitted, in which case they
% assume default values of taper=1, skew=0 and bf=1.

if nargin < 4
  taper = 1;
end
if nargin < 3
  skew = 0;
end
if nargin < 2
  bf = 1;
end

model.NB = nb;

for i = 1:nb
  model.jtype{i} = 'R';
  model.parent(i) = floor((i-2+ceil(bf))/bf);
  if model.parent(i) == 0
    model.Xtree{1} = xlt([0 0 0]);
  else
    model.Xtree{i} = rotx(skew) * xlt([len(model.parent(i)),0,0]);
  end
  len(i) = taper^(i-1);
  mass = taper^(3*(i-1));
  CoM = len(i) * [0.5,0,0];
  Icm = mass * len(i)^2 * diag([0.0025,1.015/12,1.015/12]);
  model.I{i} = mcI( mass, CoM, Icm );
end

% drawing instructions

model.appearance.base = ...
  { 'box', [-0.2 -0.3 -0.2; 0.2 0.3 -0.06] };

p0 = -1;
for i = 1:nb
  p1 = model.parent(i);
  tap = taper^(i-1);
  if p1 == 0
    ptap = 1;
  else
    ptap = taper^(p1-1);
  end
  if ( p1 > p0 )
    model.appearance.body{i} = ...
      { 'cyl', [0 0 0; 1 0 0]*tap, 0.05*tap, ...
        'cyl', [0 0 -0.07; 0 0 0.07]*ptap, 0.08*ptap };
    p0 = p1;
  else
    model.appearance.body{i} = ...
      { 'cyl', [0 0 0; 1 0 0]*tap, 0.05*tap };
  end
end
