package net.br410bury.motion;
import net.br410bury.graphics.GraphicsMatrix;
import net.br410bury.graphics.GraphicsPoint;
import java.util.ArrayList;
import net.br410bury.spacetime.Transform3D;
public class Joint
{
private final static Transform3D[] offsetchannels = {Transform3D.XTran,
Transform3D.YTran,
Transform3D.ZTran};
protected String name;
protected Joint parent = null;
protected ArrayList<Joint> children = new ArrayList<Joint>();
protected Transform3D[] channels = null;
protected double[] offsets = null;
protected int start;
protected String getStringChannels()
{
String str = "CHANNELS";
str += " " + Integer.toString(channels.length);
for(int c = 0; c < channels.length; c++)
{
switch(channels[c])
{
case XTran: str += " Xposition"; break;
case YTran: str += " Yposition"; break;
case ZTran: str += " Zposition"; break;
case XRot: str += " Xrotation"; break;
case YRot: str += " Yrotation"; break;
case ZRot: str += " Zrotation"; break;
}
}
return str;
}
protected String getStringName()
{
String str = "";
if(parent == null) str += "ROOT ";
else if(!name.equals("End Site")) str += "JOINT ";
str += name;
return str;
}
protected String getStringOffset()
{
String str = "OFFSET";
for(int o = 0; o < offsets.length; o++) str += "\t" + Double.toString(offsets[o]);
return str;
}
/**
* Blank constructor.
*/
public Joint()
{
name = "";
}
/**
* Creates a joint with the given joint name.
*
* @param jointname The name of this joint.
*/
public Joint(String jointname)
{
name = jointname;
}
/**
* Adds a child to this joint.
*
* @param joint The joint to add to the list of children of this joine.
*/
public void addChild(Joint joint)
{
children.add(joint);
}
/**
* Adds a transformation channel to this join.
*
* @param channel The channel to add.
* @param pos The position that the channel is to be added in.
*/
public void addChannel(Transform3D channel, int pos)
{
channels[pos] = channel;
}
/**
* Counts the number of nodes beneath this node in the tree.
*
* @return The number of nodes beneath this node in the tree.
*/
public int countChildren()
{
int count = children.size();
for(Joint child : children) count += child.countChildren();
return count;
}
/**
* Performs a depth first search of all the children of this joint to find the given joint
* by name.
*
* @param searchname The name to search for.
* @return The first joint encountered with the given name.
*/
public Joint findJoint(String searchname)
{
Joint joint = null;
if(name.equals(searchname)) joint = this;
for(int i = 0; joint == null && i < children.size(); i++)
{
joint = children.get(i).findJoint(searchname);
}
return joint;
}
/**
* Returns the number of transformation channels this joint has.
*
* @return The number of channels associated with this joint.
*/
public int getChannelQty()
{
return channels.length;
}
/**
* Returns the children of this joint as an ArrayList.
*
* @return An ArrayList of the children of this joint.
*/
public ArrayList<Joint> getChildren()
{
return children;
}
/**
* Returns the end channel for connection to the motion data.
*
* @return The ending channel.
*/
public int getEndChannel()
{
return this.start + (channels == null ? 0 : channels.length) - 1;
}
/**
* Returns the name of this joint.
*
* @return The name of this joint.
*/
public String getName()
{
return name;
}
/**
* Returns the offset of this joint as an array of doubles.
*
* @return The offset of this joint.
*/
public double[] getOffset()
{
double[] offset = new double[offsets.length];
System.arraycopy(offsets, 0, offset, 0, offsets.length);
return offset;
}
/**
* Gets this joints parent joint.
*
* @return This joints parent.
*/
public Joint getParent()
{
return parent;
}
/**
* Returns the transformation for this joint given a motion and a particular frame.
*
* @param frame The frame to calculate the transformation for.
* @param motion The motion which is associated with this joint.
* @return A graphics matrix describing the transformation of this joint.
*/
public GraphicsMatrix getTransformation(int frame, Motion motion)
{
GraphicsMatrix g = new GraphicsMatrix();
if(channels != null)
{
for(int ch = channels.length-1; ch >= 0; ch--)
{
if(channels[ch].isRotation())
{
g.transform(motion.getChannel(frame, start + ch) * Math.PI / 180, channels[ch]);
}
else
{
g.transform(motion.getChannel(frame, ch), channels[ch]);
}
}
}
if(parent != null) g.transform(offsets, offsetchannels);
return g;
}
/**
* Returns the translation for this joint given a motion and a particular frame.
*
* @param frame The frame to calculate the transformation for.
* @param motion The motion which is associated with this joint.
* @return A graphics matrix describing the transformation of this joint.
*/
public GraphicsMatrix getTranslation(int frame, Motion motion)
{
GraphicsMatrix g = new GraphicsMatrix();
double[] amounts;
amounts = new double[channels.length];
System.arraycopy(motion.getFrame(frame), start, amounts, 0, channels.length);
g.eye();
g.translate(amounts, channels);
return g;
}
/**
* Returns the translation for this joint given a motion and a particular frame.
*
* @param frame The frame to calculate the transformation for.
* @param motion The motion which is associated with this joint.
* @return A graphics matrix describing the transformation of this joint.
*/
public GraphicsPoint getTranslationVector(int frame, Motion motion)
{
double[] result = new double[4];
double[] motarr = motion.getFrame(frame);
for(int i = 0; i < channels.length; i++)
{
switch(channels[i])
{
case XTran: result[0] += motarr[start + i]; break;
case YTran: result[1] += motarr[start + i]; break;
case ZTran: result[2] += motarr[start + i]; break;
}
}
result[3] = 1;
return new GraphicsPoint(result);
}
/**
* Returns the rotations for this joint given a motion and a particular frame.
*
* @param frame The frame to calculate the transformation for.
* @param motion The motion which is associated with this joint.
* @return A graphics matrix describing the transformation of this joint.
*/
public GraphicsMatrix getRotation(int frame, Motion motion)
{
GraphicsMatrix g = new GraphicsMatrix();
for(int ch = channels.length-1; ch >= 0; ch--)
{
g.rotate(motion.getChannel(frame, ch) * Math.PI / 180, channels[ch]);
}
return g;
}
/**
* Returns the start channel for connection to the motion data.
*
* @return The starting channel.
*/
public int getStartChannel()
{
return this.start;
}
/**
* Returns true if this is an end site, false otherwise.
*
* @return True if this is an end site, false otherwise.
*/
public boolean isEndSite()
{
return name.equals("End Site");
}
/**
* Sets the number of channels to the given quantity.
*
* @param qty The number of channels this joint has.
*/
public void setChannels(int qty)
{
channels = new Transform3D[qty];
}
/**
* Sets the offset for this joint from its parent.
*
* @param offset The offset of this joint from its parent.
*/
public void setOffset(double[] offset)
{
offsets = (double[])offset.clone();
}
/**
* Sets the offset for this joint from its parent.
*
* @param xoffset The x offset of this joint from its parent.
* @param yoffset The y offset of this joint from its parent.
* @param zoffset The z offset of this joint from its parent.
*/
public void setOffset(double xoffset, double yoffset, double zoffset)
{
double[] offset = {xoffset, yoffset, zoffset};
offsets = offset;
}
/**
* Sets the parent of this joint.
*
* @param joint The parent of this joint.
*/
public void setParent(Joint joint)
{
parent = joint;
}
/**
* Sets the start channel for connection to the motion data
*
* @param start The start channel
*/
public void setStartChannel(int start)
{
this.start = start;
}
/**
* Returns a string representation of this joint and its children.
*
* @return A string representation of this joint and its children.
*/
public String toString()
{
return recursiveToString("");
}
/**
* Returns a string, built recursively, of this joint and its children.
*
* @param tabs The number of tabs to indent at this level.
* @return A string representation of this joint hierarchy.
*/
public String recursiveToString(String tabs)
{
String str = "";
if(parent == null) str += "HIERARCHY\n";
str += tabs + getStringName() + "\n";
str += tabs + "{\n";
str += tabs + "\t" + getStringOffset() + "\n";
if(channels != null) str += tabs + "\t" + getStringChannels() + "\n";
for(Joint child : children) str += child.recursiveToString(tabs + "\t");
str += tabs + "}\n";
return str;
}
}