package net.br410bury.formats;
import net.br410bury.graphics.GraphicsMatrix;
import net.br410bury.graphics.GraphicsPoint;
import net.br410bury.motion.Motion;
import net.br410bury.motion.Joint;
import net.br410bury.motion.Bone;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Deque;
import net.br410bury.spacetime.Transform3D;
public class BvhFormat extends MotionFormat
{
private static final GraphicsPoint matrixToPoint = new GraphicsPoint(0,0,0);
protected int channels = 0;
protected void recursiveSegment(int frame, Bone bone, Joint node, GraphicsMatrix global)
{
GraphicsMatrix local;
Bone localbone = new Bone();
local = global.times(node.getTransformation(frame, motion));
localbone.setStart(local.times(matrixToPoint));
bone.addEnd(localbone);
for(Joint child : node.getChildren())
{
if(!child.isEndSite()) recursiveSegment(frame, localbone, child, local);
}
}
protected Joint readChannels(String[] elements, Joint curr)
{
int ch = Integer.valueOf(elements[1]);
String type;
curr.setStartChannel(channels);
curr.setChannels(ch);
channels += ch;
for(int i = 0; i < ch; i++)
{
type = elements[i + 2];
if (type.contains("Xrotation")) curr.addChannel(Transform3D.XRot, i);
else if(type.contains("Yrotation")) curr.addChannel(Transform3D.YRot, i);
else if(type.contains("Zrotation")) curr.addChannel(Transform3D.ZRot, i);
else if(type.contains("Xposition")) curr.addChannel(Transform3D.XTran, i);
else if(type.contains("Yposition")) curr.addChannel(Transform3D.YTran, i);
else if(type.contains("Zposition")) curr.addChannel(Transform3D.ZTran, i);
}
return curr;
}
protected Joint readChild(String childName, Joint curr, boolean endSite)
{
Joint child;
curr.addChild(child = new Joint(childName));
child.setParent(curr);
if(!endSite) count++;
return child;
}
protected Joint readOffset(String[] elements, Joint curr)
{
double[] offset = new double[3];
offset[0] = Double.valueOf(elements[1]);
offset[1] = Double.valueOf(elements[2]);
offset[2] = Double.valueOf(elements[3]);
curr.setOffset(offset);
return curr;
}
protected void readMotion(BufferedReader in, int channels) throws IOException
{
String[] elements;
String line;
int fr = 0;
while((line = in.readLine()) != null)
{
elements = line.trim().split("\\s+");
if(line.contains("Frames"))
{
motion = new Motion(Integer.valueOf(elements[1]), channels);
}
else if(line.contains("Frame Time"))
{
motion.setFrameLength(Double.valueOf(elements[2]));
}
else
{
for(int ch = 0; ch < channels; ch++)
{
motion.setMotion(fr, ch, Double.valueOf(elements[ch]));
}
fr++;
}
}
}
protected Joint readRoot(String rootname)
{
root = new Joint(rootname);
root.setStartChannel(0);
return root;
}
/**
* Reads a file that is in proper BVH format into a skeleton and a motion.
*
* @param filename The name of the file to read the skeleton and motion from.
* @throws IOException
*/
public void read(String filename) throws IOException
{
BufferedReader in = new BufferedReader(new FileReader(filename));
Deque<Joint> deque = new ArrayDeque<Joint>();
Joint curr, child;
String[] elements;
String line;
channels = 0;
count = 1;
while((line = in.readLine()) != null)
{
elements = line.trim().split("\\s+");
curr = (deque.isEmpty() ? null : deque.pop());
child = null;
if (line.contains("OFFSET")) curr = readOffset(elements, curr);
else if(line.contains("CHANNELS")) curr = readChannels(elements, curr);
else if(line.contains("JOINT")) child = readChild(elements[1], curr, false);
else if(line.contains("End Site")) child = readChild("End Site", curr, true);
else if(line.contains("}")) curr = null;
else if(line.contains("ROOT")) deque.push(readRoot(elements[1]));
else if(line.contains("MOTION")) readMotion(in, channels);
if(curr != null) deque.push(curr);
if(child != null) deque.push(child);
}
read = true;
in.close();
}
/**
* Writes the skeleton and motion to a BVH file. Currently not implemented.
*
* @param filename The file to save the skeleton and motion to.
* @throws IOException
* @throws FileNotFoundException
*/
public void save(String filename) throws IOException
{
BufferedWriter out;
out = new BufferedWriter(new FileWriter(filename));
out.write(root.toString());
out.write(motion.toString());
out.close();
}
/**
* Segments all frames.
*/
public void segment()
{
GraphicsMatrix global;
rootbone = new Bone[motion.getFrames()];
for(int frame = 0; frame < motion.getFrames(); frame++) segment(frame);
}
/**
* Segments the given frame.
*
* @param frame The frame to segment.
*/
public void segment(int frame)
{
GraphicsMatrix global;
if(rootbone == null) rootbone = new Bone[motion.getFrames()];
if(rootbone[frame] == null)
{
rootbone[frame] = new Bone();
global = root.getTransformation(frame, motion);
rootbone[frame].setStart(global.times(matrixToPoint));
for(Joint child : root.getChildren())
{
recursiveSegment(frame, rootbone[frame], child, global);
}
}
}
/**
* Returns a string representation of this object.
*
* @return A string representation of this object.
*/
public String toString()
{
String str = "";
str += root + "\n" + motion + "\nCount:" + Integer.toString(count);
return str;
}
}