Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

RotationInterpolationCompressor.cpp

Go to the documentation of this file.
00001 //------------------------------------------------------------------------------
00002 // Lamp : Open source game middleware
00003 // Copyright (C) 2004  Junpei Ohtani ( Email : junpee@users.sourceforge.jp )
00004 //
00005 // This library is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 //
00010 // This library is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with this library; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 //------------------------------------------------------------------------------
00019 
00020 /** @file
00021  * 回転補間圧縮実装
00022  * @author Junpee
00023  */
00024 
00025 #include "LampBasic.h"
00026 #include "Animation/RotationInterpolator/RotationInterpolationCompressor.h"
00027 #include "Animation/RotationInterpolator/QuaternionArrayInterpolator.h"
00028 #include "Animation/RotationInterpolator/EulerArrayInterpolator.h"
00029 #include "Animation/RotationInterpolator/RotationConstantInterpolator.h"
00030 #include "Animation/RotationInterpolator/QuaternionLinearInterpolator.h"
00031 #include "Core/Container/Deque.h"
00032 
00033 namespace Lamp{
00034 
00035 //------------------------------------------------------------------------------
00036 // 生成、破棄
00037 //------------------------------------------------------------------------------
00038 // コンストラクタ
00039 RotationInterpolationCompressor::RotationInterpolationCompressor() :
00040     tolerance_(0.f), length_(0.f), sourceKeyCount_(0), compressedKeyCount_(0),
00041     compressedKeySize_(0){
00042 }
00043 //------------------------------------------------------------------------------
00044 // デストラクタ
00045 RotationInterpolationCompressor::~RotationInterpolationCompressor(){
00046 }
00047 //------------------------------------------------------------------------------
00048 // 圧縮
00049 //------------------------------------------------------------------------------
00050 // 圧縮
00051 RotationInterpolator* RotationInterpolationCompressor::compress(
00052     EulerArrayInterpolator* source, float tolerance){
00053     // 四元数回転配列補間に変換して圧縮する
00054     QuaternionArrayInterpolator* interpolator =
00055         source->convertQuaternionArrayInterpolator();
00056     RotationInterpolator* result = compress(interpolator, tolerance);
00057     delete interpolator;
00058     return result;
00059 }
00060 //------------------------------------------------------------------------------
00061 // 圧縮
00062 RotationInterpolator* RotationInterpolationCompressor::compress(
00063     QuaternionArrayInterpolator* source, float tolerance){
00064     // 圧縮準備
00065     compressSetup(source, tolerance);
00066     RotationInterpolator* result = NULL;
00067 
00068     // 定数圧縮
00069     result = compressConstant(source);
00070     if(result != NULL){ return result; }
00071 
00072     // 線形圧縮
00073     result = compressLinear(source);
00074     if(result != NULL){ return result; }
00075 
00076     // スプライン系の圧縮と線形圧縮の結果を重み付けした上で比較して出力可能
00077     // その場合にsetCompressedDataを忘れないように注意
00078 
00079     // 全ての圧縮に失敗したなら元データのコピーを返す
00080     result = source->duplicate();
00081     setCompressedData(getSourceKeyCount(), sourceKeySize_);
00082     
00083     return result;
00084 }
00085 //------------------------------------------------------------------------------
00086 // 圧縮準備
00087 void RotationInterpolationCompressor::compressSetup(
00088     QuaternionArrayInterpolator* source, float tolerance){
00089     Assert(source != NULL); 
00090     Assert((tolerance >= 0.f) && (tolerance < Math::halfPI));
00091     tolerance_ = tolerance;
00092     length_ = source->getLength();
00093     sourceKeyCount_ = source->getSize();
00094     Assert(sourceKeyCount_ > 1);
00095 }
00096 //------------------------------------------------------------------------------
00097 // 定数圧縮
00098 RotationInterpolator* RotationInterpolationCompressor::compressConstant(
00099     QuaternionArrayInterpolator* source){
00100     // ターゲットとなる値の算出、最初の値を使用する
00101     const Quaternion& targetValue = source->getValue(0);
00102     Assert(targetValue.isUnit());
00103 
00104     // 誤差チェック
00105     float toleranceCos = Math::cos(getTolerance());
00106     for(int i = 0; i < sourceKeyCount_; i++){
00107         const Quaternion& sourceValue = source->getValue(i);
00108         Assert(sourceValue.isUnit());
00109         // 定数圧縮に失敗
00110         if(targetValue.dotProduct(sourceValue) < toleranceCos){ return NULL; }
00111     }
00112 
00113     // 定数圧縮に成功
00114     RotationConstantInterpolator* result = new RotationConstantInterpolator();
00115     result->setLength(getLength());
00116     result->setQuaternion(targetValue);
00117     setCompressedData(1, sizeof(Quaternion) + sizeof(float));
00118     return result;
00119 }
00120 //------------------------------------------------------------------------------
00121 // 線形圧縮
00122 RotationInterpolator* RotationInterpolationCompressor::compressLinear(
00123     QuaternionArrayInterpolator* source){
00124     // キーのリストを作成し、誤差が小さいキーから間引いていく
00125 
00126     // キーリストの作成
00127     int sourceKeyCount = getSourceKeyCount();
00128     Deque<LinearKey> keys_(sourceKeyCount);
00129     for(int i = 0; i < sourceKeyCount; i++){
00130         LinearKey key;
00131         key.value_ = source->getValue(i);
00132         key.time_ = (float)i;
00133         keys_.pushBack(key);
00134     }
00135 
00136     // 全誤差の算出
00137     int keyCount = keys_.getCount();
00138     int maxKeyCount = keyCount - 1;
00139     // 最初と最後の値は操作しない
00140     keys_[0].errorCos_ = 1.f;
00141     keys_[maxKeyCount].errorCos_ = 1.f;
00142     Assert(keys_[0].time_ == 0.f)
00143     Assert(keys_[maxKeyCount].time_ == getLength());
00144     Assert(keys_[0].value_.dotProduct(keys_[1].value_) >= 0.f);
00145     for(int i = 1; i < maxKeyCount; i++){
00146         LinearKey& key = keys_[i];
00147         LinearKey& preKey = keys_[i - 1];
00148         LinearKey& postKey = keys_[i + 1];
00149         Assert(key.value_.dotProduct(postKey.value_) >= 0.f);
00150         // 前のキーと後ろのキーの中間の値との誤差
00151         Quaternion value =
00152             Quaternion::slerp(preKey.value_, postKey.value_, 0.5f);
00153         key.errorCos_ = key.value_.dotProduct(value);
00154     }
00155 
00156     // 圧縮ループ、キーが2個になったら抜ける
00157     float toleranceCos = Math::cos(getTolerance());
00158     while(keys_.getCount() > 2){
00159         // 誤差が最小のキーを調べる
00160         int targetIndex = 0;
00161         float targetErrorCos = -1.f;
00162         maxKeyCount = keys_.getCount() - 1;
00163         for(int i = 1; i < maxKeyCount; i++){
00164             // Cosがより1に近いと誤差が小さい
00165             // 前と後ろのキーの内積が0以上
00166 //          if(keys_[i].errorCos_ > targetErrorCos){
00167             if((keys_[i].errorCos_ > targetErrorCos) &&
00168                 (keys_[i - 1].value_.dotProduct(keys_[i + 1].value_) >= 0.f)){
00169                 targetErrorCos = keys_[i].errorCos_;
00170                 targetIndex = i;
00171             }
00172         }
00173 
00174         // ターゲットが見つからなかった
00175         if(targetIndex == 0){ break; }
00176         // 最小誤差が許容範囲外なら圧縮ループを抜ける
00177         if(targetErrorCos < toleranceCos){ break; }
00178 
00179         // 最小誤差キーの削除と誤差のアップデート
00180         keys_.remove(targetIndex);
00181         // 前のキーが先頭キーでなければ誤差を再計算
00182         if((targetIndex - 1) > 0){
00183             recalcLinearError(source, keys_[targetIndex - 2],
00184                 keys_[targetIndex - 1], keys_[targetIndex]);
00185         }
00186         // 後ろのキーが最後尾キーでなければ誤差を再計算
00187         if(targetIndex < (keys_.getCount() - 1)){
00188             recalcLinearError(source, keys_[targetIndex - 1],
00189                 keys_[targetIndex], keys_[targetIndex + 1]);
00190         }
00191     }
00192 
00193     // サイズが小さくなっていなければ失敗、失敗条件を厳しくするのもあり
00194     keyCount = keys_.getCount();
00195     int keySize = sizeof(Quaternion) + sizeof(float);
00196     if((keyCount * keySize) >= getSourceSize()){ return NULL; }
00197 
00198     // 線形圧縮に成功
00199     QuaternionLinearInterpolator* result = new QuaternionLinearInterpolator();
00200     result->setKeyCount(keyCount);
00201     for(int i = 0; i < keyCount; i++){
00202         LinearKey& key = keys_[i];
00203         result->setKey(i, key.time_, key.value_);
00204     }
00205     setCompressedData(keyCount, keySize);
00206     return result;
00207 }
00208 //------------------------------------------------------------------------------
00209 // 線形圧縮誤差の再計算
00210 void RotationInterpolationCompressor::recalcLinearError(
00211     QuaternionArrayInterpolator* source,
00212     LinearKey& preKey, LinearKey& key, LinearKey& postKey){
00213     int preTime = (int)preKey.time_;
00214     Quaternion preValue = preKey.value_;
00215     int postTime = (int)postKey.time_;
00216     Quaternion postValue = postKey.value_;
00217     int timeRange = postTime - preTime;
00218 
00219     // 最大誤差のCosを算出
00220     float maxErrorCos = 1.f;
00221     for(int i = 1; i < timeRange; i++){
00222         int time = preTime + i;
00223         Quaternion sourceValue = source->getValue(time);
00224         float rate = (float)i / (float)timeRange;
00225         Quaternion targetValue = Quaternion::slerp(preValue, postValue, rate);
00226         float errorCos = sourceValue.dotProduct(targetValue);
00227         if(errorCos < maxErrorCos){ maxErrorCos = errorCos; }
00228     }
00229     key.errorCos_ = maxErrorCos;
00230 }
00231 //------------------------------------------------------------------------------
00232 // 圧縮結果
00233 //------------------------------------------------------------------------------
00234 // 結果文字列の取得
00235 String RotationInterpolationCompressor::getResultString() const{
00236     String result;
00237     result.format(
00238         "%.2f%%  Key %d/%d  Size %.2f/%.2fKb  Length %.0f",
00239         getCompressionRate() * 100.f,
00240         getCompressedKeyCount(), getSourceKeyCount(),
00241         (float)getCompressedSize() / 1024.f, (float)getSourceSize() / 1024.f,
00242         getLength());
00243     return result;
00244 }
00245 //------------------------------------------------------------------------------
00246 } // End of namespace Lamp
00247 //------------------------------------------------------------------------------

Generated on Wed Mar 16 10:29:34 2005 for Lamp by doxygen 1.3.2