pxmlw6n2f/Gazebo_Distributed/gazebo/common/BVHLoader.cc

274 lines
7.8 KiB
C++

/*
* Copyright (C) 2012 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <algorithm>
#include <fstream>
#include <sstream>
#include <boost/algorithm/string.hpp>
#include <ignition/math/Vector3.hh>
#include <ignition/math/Matrix4.hh>
#include "gazebo/common/CommonIface.hh"
#include "gazebo/common/BVHLoader.hh"
#include "gazebo/common/SystemPaths.hh"
#include "gazebo/common/Skeleton.hh"
#include "gazebo/common/SkeletonAnimation.hh"
#include "gazebo/common/Console.hh"
using namespace gazebo;
using namespace common;
/////////////////////////////////////////////////
BVHLoader::BVHLoader()
{
}
/////////////////////////////////////////////////
BVHLoader::~BVHLoader()
{
}
/////////////////////////////////////////////////
Skeleton *BVHLoader::Load(const std::string &_filename, double _scale)
{
std::string fullname = common::find_file(_filename);
Skeleton *skeleton = NULL;
std::ifstream file;
file.open(fullname.c_str());
std::vector<SkeletonNode*> nodes;
std::vector<std::vector<std::string> > nodeChannels;
unsigned int totalChannels = 0;
std::string line;
if (file.is_open())
{
getline(file, line);
if (line.find("HIERARCHY") == std::string::npos)
{
file.close();
return NULL;
}
SkeletonNode *parent = NULL;
SkeletonNode *node = NULL;
while (!file.eof())
{
getline(file, line);
std::vector<std::string> words;
boost::trim(line);
boost::split(words, line, boost::is_any_of(" "));
if (words[0] == "ROOT" || words[0] == "JOINT")
{
if (words.size() < 2)
{
file.close();
return NULL;
}
SkeletonNode::SkeletonNodeType type = SkeletonNode::JOINT;
std::string name = words[1];
node = new SkeletonNode(parent, name, name, type);
if (words[0] != "End")
nodes.push_back(node);
}
else
if (words[0] == "OFFSET")
{
if (words.size() < 4)
{
file.close();
return NULL;
}
ignition::math::Vector3d offset = ignition::math::Vector3d(
ignition::math::parseFloat(words[1]) * _scale,
ignition::math::parseFloat(words[2]) * _scale,
ignition::math::parseFloat(words[3]) * _scale);
ignition::math::Matrix4d transform(
ignition::math::Matrix4d::Identity);
transform.Translate(offset);
node->SetTransform(transform);
}
else
if (words[0] == "CHANNELS")
{
if (words.size() < 3 ||
static_cast<size_t>(ignition::math::parseInt(words[1]) + 2) >
words.size())
{
file.close();
return NULL;
}
nodeChannels.push_back(words);
totalChannels += ignition::math::parseInt(words[1]);
}
else
if (words[0] == "{")
parent = node;
else
if (words[0] == "}")
parent = parent->GetParent();
else
if (words.size() == 2 && words[0] == "End"
&& words[1] == "Site")
{
/// ignore End Sites
getline(file, line); /// read {
getline(file, line); /// read OFFSET
getline(file, line); /// read }
}
else
{
if (nodes.empty())
{
file.close();
return NULL;
}
skeleton = new Skeleton(nodes[0]);
break;
}
}
}
getline(file, line);
std::vector<std::string> words;
boost::trim(line);
boost::split(words, line, boost::is_any_of(" "));
unsigned int frameCount = 0;
double frameTime = 0.0;
if (words[0] != "Frames:" || words.size() < 2)
{
file.close();
return NULL;
}
else
frameCount = ignition::math::parseInt(words[1]);
getline(file, line);
words.clear();
boost::trim(line);
boost::split(words, line, boost::is_any_of(" "));
if (words.size() < 3 || words[0] != "Frame" || words[1] != "Time:")
{
file.close();
return NULL;
}
else
frameTime = ignition::math::parseFloat(words[2]);
double time = 0.0;
unsigned int frameNo = 0;
SkeletonAnimation *animation = new SkeletonAnimation(_filename);
while (!file.eof())
{
getline(file, line);
words.clear();
boost::trim(line);
boost::split(words, line, boost::is_any_of(" "));
if (words.size() < totalChannels)
{
gzwarn << "Frame " << frameNo << " invalid.\n";
frameNo++;
time += frameTime;
continue;
}
unsigned int cursor = 0;
for (unsigned int i = 0; i < nodes.size(); ++i)
{
SkeletonNode *node = nodes[i];
std::vector<std::string> channels = nodeChannels[i];
ignition::math::Vector3d translation = node->Transform().Translation();
ignition::math::Vector3d xAxis(1, 0, 0);
ignition::math::Vector3d yAxis(0, 1, 0);
ignition::math::Vector3d zAxis(0, 0, 1);
double xAngle = 0.0;
double yAngle = 0.0;
double zAngle = 0.0;
ignition::math::Matrix4d transform(ignition::math::Matrix4d::Identity);
std::vector<ignition::math::Matrix4d> mats;
unsigned int chanCount = ignition::math::parseInt(channels[1]);
for (unsigned int j = 2; j < (2 + chanCount); ++j)
{
double value = ignition::math::parseFloat(words[cursor]);
cursor++;
std::string channel = channels[j];
if (channel == "Xposition")
translation.X(value * _scale);
else
if (channel == "Yposition")
translation.Y(value * _scale);
else
{
if (channel == "Zposition")
{
translation.Z(value * _scale);
}
else
{
if (channel == "Zrotation")
{
zAngle = GZ_DTOR(value);
mats.push_back(ignition::math::Matrix4d(
ignition::math::Quaterniond(zAxis, zAngle)));
}
else
{
if (channel == "Xrotation")
{
xAngle = GZ_DTOR(value);
mats.push_back(ignition::math::Matrix4d(
ignition::math::Quaterniond(xAxis, xAngle)));
}
else
{
if (channel == "Yrotation")
{
yAngle = GZ_DTOR(value);
mats.push_back(ignition::math::Matrix4d(
ignition::math::Quaterniond(yAxis, yAngle)));
}
}
}
}
}
}
while (!mats.empty())
{
transform = mats.back() * transform;
mats.pop_back();
}
ignition::math::Matrix4d pos(ignition::math::Matrix4d::Identity);
pos.Translate(translation);
transform = pos * transform;
animation->AddKeyFrame(node->GetName(), time, transform);
}
frameNo++;
time += frameTime;
if (frameNo == frameCount)
break;
}
if (frameNo < frameCount - 1)
gzwarn << "BVH file ended unexpectedly.\n";
skeleton->AddAnimation(animation);
file.close();
return skeleton;
}