您的位置:首页 > 编程语言 > Java开发

BVH文件 Java解析器

2016-03-25 14:49 706 查看

BVH文件解析器

BVH文件解析器
简介

解析器

源码

谢谢

简介

对于BVH文件的格式,可以参考:BVH文件格式解析

解析器

使用java编写,具体使用方法:

导入google的gson包,用来生成json:

如果是eclipse,下载jar导入到项目中:gson jar下载

如果是使用IDEA,则通过File - Project Structure - Modules - Dependencies - +(加号) - Libraries - From Mave, 搜索gson,添加com.google.gson.Gson;

创建
BVHParser
的类对象:

BVHParser parser = new BVHParser();


传入bvh文件的绝对路径,调用
parse(String)
方法解析得到json格式的字符串:

String json = parser.parse("your absoulte path of the .bvh file's ");


如果要写入文件:

File out = new File("out.json"); // print to a json file
try {
PrintStream ps = new PrintStream(new FileOutputStream(out));
ps.println(json);
} catch (IOException e) {
e.printStackTrace();
} finally {
parser.release();
}


最后释放I/O

parser.release();


源码

对于逻辑,部分已在代码中注释

import com.google.gson.Gson;

import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;

/**
* Parsing the standard .bvh file, some infor cannot be tranfered to json if not a standard .bvh file
* Only get segment's data without motion's data.
* <p>
* The parser need external library: com.google.code.gson:gson
* <p>
* Created by PentonBin on 16-3-23.
*/
public class BVHParser {

private static final String TAG = "BVHParser";

private static final String KEYWORD_HIERARCHY = "HIERARCHY";
private static final String KEYWORD_ROOT = "ROOT";
private static final String KEYWORD_OFFSET = "OFFSET";
private static final String KEYWORD_CHANNELS = "CHANNELS";
private static final String KEYWORD_JOINT = "JOINT";
private static final String KEYWORD_END_SITE = "End Site";
private static final String KEYWORD_MOTION = "MOTION";
private static final String KEYWORD_FRAME = "Frames";
private static final String KEYWORD_FRAME_TIME = "Frame Time";

private static final int NUM_OFFSET = 3;
private static final int NUM_ROOT_CHANNELS = 6;
private static final int NUM_JOINT_CHANNELS = 3;

private BufferedReader mParseReader;
private boolean isReaderMarkConsume = true;

enum SegmentType {
Root, Joint, EndSite
}

enum ChannelType {
Xposition, Yposition, Zposition, Zrotation, Xrotation, Yrotation
}

static class Segment {
private String name;
private SegmentType type;
private ArrayList<Double> offsetValueList;
private int channelsNum;
private ArrayList<ChannelType> channelTypeList;
private ArrayList<Segment> subSegments;

public Segment() {
}

public void putOffset(double offset) {
if (offsetValueList == null) {
offsetValueList = new ArrayList<Double>();
}
offsetValueList.add(offset);
}

public void setChannelsNum(int channelsNum) {
this.channelsNum = channelsNum;
}

public void putChannelType(ChannelType type) {
if (channelTypeList == null) {
channelTypeList = new ArrayList<ChannelType>();
}
channelTypeList.add(type);
}

public void setName(String name) {
this.name = name;
}

public void setSegmentType(SegmentType type) {
this.type = type;
}

public SegmentType getType() {
return type;
}

public void putSubSegment(Segment subSegment) {
if (subSegments == null) {
subSegments = new ArrayList<Segment>();
}
subSegments.add(subSegment);
}
}

static class Motion {
private int framesNum;
private double framesTime;
private ArrayList<Double> motionsData;

public Motion() {
}
}

/**
* Parse the .bvh file provided by {@param filePath}
*
* @param filePath the path of the file
* @return String of the json format, null if the file does not exist or is not file
*/
public String parse(String filePath) {
File file = new File(filePath);
if (file != null && file.exists() && file.isFile()) {
Gson gson = new Gson();
Segment rootSegment = getSegmentFromFile(file);
return gson.toJson(rootSegment);
}
return null;
}

/**
* Must call this function to release the I/O after parsing the .bvh file
*/
public void release() {
if (mParseReader != null) {
try {
mParseReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

private Segment getSegmentFromFile(File file) {
mParseReader = getFileBufferedReader(file);
if (mParseReader == null) {
return null;
}
try {
String header = mParseReader.readLine().trim();
if (!readFileHeader(header)) {
throw new IllegalArgumentException("File : " + file.getName() + " is not a .bvh file");
}
return parseSegment(mParseReader);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

/**
* Parsing the header of the .bvh file
*
* @param header the header string of the .bvh file
* @return true if the header is real header of the .bvh file, else return false
*/
private static boolean readFileHeader(String header) {
if (header == null || header.equalsIgnoreCase("")) {
return false;
}
if (header.equalsIgnoreCase(KEYWORD_HIERARCHY)) {
return true;
}
return false;
}

private Segment parseSegment(BufferedReader reader) {
if (reader == null) {
return null;
}
try {
Segment segment = new Segment();
String line = reader.readLine().trim(); // Header of segment

readSegmentFromeHeadString(segment, line);
line = reader.readLine().trim();
if (line.equals("{")) { // left curly brace
// do nothing
} else {
System.out.println("Error : left curly brace");
System.exit(-1);
}
line = reader.readLine().trim(); // offset
readOffsetsFromString(segment, line);
if (segment.type.equals(SegmentType.Root)) {
line = reader.readLine().trim(); // channel
readChannelsFromString(segment, line);

while (true) {
markReader(reader); // mark if need to call reset()
line = reader.readLine().trim(); // get the next line to judge whether have a subsegment
if (line.startsWith(KEYWORD_JOINT)) { // should call reset if has subsegment
resetReader(reader);
segment.putSubSegment(parseSegment(reader));
} else {
consumeMark(); // has no subsegment, dismark the reader
break;
}
}
} else if (segment.type.equals(SegmentType.Joint)) {
line = reader.readLine().trim(); // channel
readChannelsFromString(segment, line);

while (true) {
markReader(reader); // mark
line = reader.readLine().trim();
if (line.equalsIgnoreCase("}")) { // end joint
consumeMark(); // no subsegment, dismark
break;
}
if (line.startsWith(KEYWORD_JOINT)) { // has subsegment
resetReader(reader); // reset
segment.putSubSegment(parseSegment(reader));  // put joint
} else if (line.startsWith(KEYWORD_END_SITE)) {
resetReader(reader);
segment.putSubSegment(parseSegment(reader)); // put endsite
}
}
} else if (segment.type.equals(SegmentType.EndSite)) {
// end parsing, no more data
line = reader.readLine().trim(); // right curly brace
if (line.equalsIgnoreCase("}")) {
// do nothing
} else {
System.out.println("Error : right curly brace");
System.exit(-1);
}
}
return segment;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

/**
* Parsing the string of a segment's head
*
* @param segment       the header of this segment
* @param segmentHeader the string of the segment's head
*/
private static void readSegmentFromeHeadString(Segment segment, String segmentHeader) {
if (segmentHeader == null || segmentHeader.equalsIgnoreCase("")) {
return;
}
String[] splits = segmentHeader.split(" ");
if (splits[0].equalsIgnoreCase(KEYWORD_ROOT)) {
segment.setSegmentType(SegmentType.Root);
segment.setName(splits[1]);
} else if (splits[0].equalsIgnoreCase(KEYWORD_JOINT)) {
segment.setSegmentType(SegmentType.Joint);
segment.setName(splits[1]);
} else if (segmentHeader.equalsIgnoreCase(KEYWORD_END_SITE)) {
segment.setSegmentType(SegmentType.EndSite); // End site has no name
}
}

/**
* Parsing the string of the segment's offset
*
* @param segment      the offset of this segment
* @param offsetString the string of the segment's offset
*/
private static void readOffsetsFromString(Segment segment, String offsetString) {
if (offsetString == null || offsetString.equalsIgnoreCase("")) {
return;
}
String[] splits = offsetString.split(" "); // may contains '\t' instead of ' '
if (!splits[0].equalsIgnoreCase(KEYWORD_OFFSET)) {
splits = offsetString.split("\\t");
if (!splits[0].equalsIgnoreCase(KEYWORD_OFFSET)) {
return;
}
}
if (segment != null) {
for (int i = 1; i <= NUM_OFFSET; ++i) {
try {
double offset = Double.parseDouble(splits[i]);
segment.putOffset(offset);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

/**
* Parsing the string of the segment's channel
*
* @param segment       the channel of this segment
* @param channelString the string of the segment's channel
*/
private static void readChannelsFromString(Segment segment, String channelString) {
if (channelString == null || channelString.equalsIgnoreCase("")) {
return;
}
String[] splits = channelString.split(" ");
if (!splits[0].equalsIgnoreCase(KEYWORD_CHANNELS)) {
return;
}
if (segment != null) {
try {
int channelsNum = Integer.parseInt(splits[1]);
segment.setChannelsNum(channelsNum);
for (int i = 2; i < 2 + channelsNum; ++i) {
ChannelType channelType = ChannelType.valueOf(ChannelType.class, splits[i]);
segment.putChannelType(channelType);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

/**
* Get the BufferReader of the file
*
* @param file
* @return the BufferReader of {@param file}
*/
private BufferedReader getFileBufferedReader(File file) {
if (file == null || !file.exists() || !file.isFile()) {
return null;
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
return reader;
} catch (Exception e) {
e.printStackTrace();
}
return reader;
}

/**
* To use the function reset() of the BufferReader, should call mark(int) first,
* mark(int) need a param: readAheadLimit, it's recorded by a field of BufferReader,
* using reflection to get the value of the field which named "nextChar"
*
* @param reader to get this reader's field
* @return the field value of the {@param reader}
*/
private static int getReaderNextChar(BufferedReader reader) {
Class<?> clazz = BufferedReader.class;
try {
Field nextCharField = clazz.getDeclaredField("nextChar");
nextCharField.setAccessible(true);
return nextCharField.getInt(reader);
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}

/**
* It's necessary to call BufferReader.mark(int) when call BufferReader.reset()
*
* To reset only once, using the field {@field isReaderMarkConsume} to control
*
* @param reader the reader we want to mark
*/
private void markReader(BufferedReader reader) {
try {
reader.mark(getReaderNextChar(reader));
isReaderMarkConsume = false;
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* If the reader was marked, using this function to dismark the reader
*/
private void consumeMark() {
isReaderMarkConsume = true;
}

/**
* When using BufferReader.readLine(), we need to call reset() when sometime need to rollback to the privious line,
* it's necessary to call mark(int) before calling reset(), the function of the {@function markReader} is to mark the reader
*
* To reset only once, using the field {@field isReaderMarkConsume} to control
*
* @param reader the reader we want to reset
*/
private void resetReader(BufferedReader reader) {
try {
if (!isReaderMarkConsume) {
reader.reset();
isReaderMarkConsume = true;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}


谢谢

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java BVH 解析 代码