pxmlw6n2f/Gazebo_Distributed_MPI/gazebo/common/Animation.cc

328 lines
7.9 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 <ignition/math/Spline.hh>
#include <ignition/math/RotationSpline.hh>
#include "gazebo/common/Console.hh"
#include "gazebo/common/KeyFrame.hh"
#include "gazebo/common/Animation.hh"
using namespace gazebo;
using namespace common;
namespace
{
struct KeyFrameTimeLess
{
bool operator() (const common::KeyFrame *_kf,
const common::KeyFrame *_kf2) const
{
return _kf->GetTime() < _kf2->GetTime();
}
};
}
/////////////////////////////////////////////////
Animation::Animation(const std::string &_name, double _length, bool _loop)
: name(_name), length(_length), loop(_loop)
{
this->timePos = 0;
this->build = false;
}
/////////////////////////////////////////////////
Animation::~Animation()
{
}
/////////////////////////////////////////////////
double Animation::GetLength() const
{
return this->length;
}
/////////////////////////////////////////////////
void Animation::SetLength(double _len)
{
this->length = _len;
}
/////////////////////////////////////////////////
void Animation::SetTime(double _time)
{
if (!ignition::math::equal(_time, this->timePos))
{
this->timePos = _time;
if (this->loop)
{
this->timePos = fmod(this->timePos, this->length);
if (this->timePos < 0)
this->timePos += this->length;
}
else
{
if (this->timePos < 0)
this->timePos = 0;
else if (this->timePos > this->length)
this->timePos = this->length;
}
}
}
/////////////////////////////////////////////////
void Animation::AddTime(double _time)
{
this->SetTime(this->timePos + _time);
}
/////////////////////////////////////////////////
double Animation::GetTime() const
{
return this->timePos;
}
/////////////////////////////////////////////////
unsigned int Animation::GetKeyFrameCount() const
{
return this->keyFrames.size();
}
/////////////////////////////////////////////////
KeyFrame *Animation::GetKeyFrame(unsigned int _index) const
{
KeyFrame *result = NULL;
if (_index < this->keyFrames.size())
result = this->keyFrames[_index];
else
{
gzerr << "Key frame index[" << _index
<< "] is larger than key frame array size["
<< this->keyFrames.size() << "]\n";
}
return result;
}
/////////////////////////////////////////////////
double Animation::GetKeyFramesAtTime(double _time, KeyFrame **_kf1,
KeyFrame **_kf2,
unsigned int &_firstKeyIndex) const
{
// Parametric time
// t1 = time of previous keyframe
// t2 = time of next keyframe
double t1, t2;
// Find first key frame after or on current time
while (_time > this->length && this->length > 0.0)
_time -= this->length;
KeyFrame_V::const_iterator iter;
KeyFrame timeKey(_time);
iter = std::lower_bound(this->keyFrames.begin(), this->keyFrames.end(),
&timeKey, KeyFrameTimeLess());
if (iter == this->keyFrames.end())
{
// There is no keyframe after this time, wrap back to first
*_kf2 = this->keyFrames.front();
t2 = this->length + (*_kf2)->GetTime();
// Use the last keyframe as the previous keyframe
--iter;
}
else
{
*_kf2 = *iter;
t2 = (*_kf2)->GetTime();
// Find last keyframe before or on current time
if (iter != this->keyFrames.begin() && _time < (*iter)->GetTime())
--iter;
}
_firstKeyIndex = std::distance(this->keyFrames.begin(), iter);
*_kf1 = *iter;
t1 = (*_kf1)->GetTime();
if (ignition::math::equal(t1, t2))
return 0.0;
else
return (_time - t1) / (t2 - t1);
}
/////////////////////////////////////////////////
PoseAnimation::PoseAnimation(const std::string &_name,
double _length, bool _loop)
: Animation(_name, _length, _loop)
{
this->positionSpline = NULL;
this->rotationSpline = NULL;
}
/////////////////////////////////////////////////
PoseAnimation::~PoseAnimation()
{
delete this->positionSpline;
delete this->rotationSpline;
}
/////////////////////////////////////////////////
PoseKeyFrame *PoseAnimation::CreateKeyFrame(double _time)
{
PoseKeyFrame *frame = new PoseKeyFrame(_time);
std::vector<KeyFrame*>::iterator iter =
std::upper_bound(this->keyFrames.begin(), this->keyFrames.end(),
reinterpret_cast<KeyFrame*>(frame), KeyFrameTimeLess());
this->keyFrames.insert(iter, frame);
this->build = true;
return frame;
}
/////////////////////////////////////////////////
void PoseAnimation::BuildInterpolationSplines() const
{
if (!this->positionSpline)
this->positionSpline = new ignition::math::Spline();
if (!this->rotationSpline)
this->rotationSpline = new ignition::math::RotationSpline();
this->positionSpline->AutoCalculate(false);
this->rotationSpline->AutoCalculate(false);
this->positionSpline->Clear();
this->rotationSpline->Clear();
for (KeyFrame_V::const_iterator iter = this->keyFrames.begin();
iter != this->keyFrames.end(); ++iter)
{
PoseKeyFrame *pkey = reinterpret_cast<PoseKeyFrame*>(*iter);
this->positionSpline->AddPoint(pkey->Translation());
this->rotationSpline->AddPoint(pkey->Rotation());
}
this->positionSpline->RecalcTangents();
this->rotationSpline->RecalcTangents();
this->build = false;
}
/////////////////////////////////////////////////
void PoseAnimation::GetInterpolatedKeyFrame(PoseKeyFrame &_kf) const
{
this->GetInterpolatedKeyFrame(this->timePos, _kf);
}
/////////////////////////////////////////////////
void PoseAnimation::GetInterpolatedKeyFrame(double _time,
PoseKeyFrame &_kf) const
{
KeyFrame *kBase1, *kBase2;
PoseKeyFrame *k1;
unsigned int firstKeyIndex;
if (this->build)
this->BuildInterpolationSplines();
double t = this->GetKeyFramesAtTime(_time, &kBase1, &kBase2, firstKeyIndex);
k1 = reinterpret_cast<PoseKeyFrame*>(kBase1);
if (ignition::math::equal(t, 0.0))
{
_kf.Translation(k1->Translation());
_kf.Rotation(k1->Rotation());
}
else
{
_kf.Translation(this->positionSpline->Interpolate(firstKeyIndex, t));
_kf.Rotation(this->rotationSpline->Interpolate(firstKeyIndex, t));
}
}
/////////////////////////////////////////////////
NumericAnimation::NumericAnimation(const std::string &_name,
double _length, bool _loop)
: Animation(_name, _length, _loop)
{
}
/////////////////////////////////////////////////
NumericAnimation::~NumericAnimation()
{
}
/////////////////////////////////////////////////
NumericKeyFrame *NumericAnimation::CreateKeyFrame(double _time)
{
NumericKeyFrame *frame = new NumericKeyFrame(_time);
std::vector<KeyFrame*>::iterator iter =
std::upper_bound(this->keyFrames.begin(), this->keyFrames.end(),
reinterpret_cast<KeyFrame*>(frame),
KeyFrameTimeLess());
this->keyFrames.insert(iter, frame);
this->build = true;
return frame;
}
/////////////////////////////////////////////////
void NumericAnimation::GetInterpolatedKeyFrame(NumericKeyFrame &_kf) const
{
// Keyframe pointers
KeyFrame *kBase1, *kBase2;
NumericKeyFrame *k1, *k2;
unsigned int firstKeyIndex;
double t;
t = this->GetKeyFramesAtTime(this->timePos, &kBase1, &kBase2, firstKeyIndex);
k1 = reinterpret_cast<NumericKeyFrame*>(kBase1);
k2 = reinterpret_cast<NumericKeyFrame*>(kBase2);
if (ignition::math::equal(t, 0.0))
{
// Just use k1
_kf.SetValue(k1->GetValue());
}
else
{
// Interpolate by t
double diff = k2->GetValue() - k1->GetValue();
_kf.SetValue(k1->GetValue() + diff * t);
}
}