Field3D
Curve.h
Go to the documentation of this file.
00001 //----------------------------------------------------------------------------//
00002 
00003 /*
00004  * Copyright (c) 2009 Sony Pictures Imageworks Inc
00005  *
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  *
00012  * Redistributions of source code must retain the above copyright
00013  * notice, this list of conditions and the following disclaimer.
00014  * Redistributions in binary form must reproduce the above copyright
00015  * notice, this list of conditions and the following disclaimer in the
00016  * documentation and/or other materials provided with the
00017  * distribution.  Neither the name of Sony Pictures Imageworks nor the
00018  * names of its contributors may be used to endorse or promote
00019  * products derived from this software without specific prior written
00020  * permission.
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00025  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
00026  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00027  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00028  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00029  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
00031  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
00033  * OF THE POSSIBILITY OF SUCH DAMAGE.
00034  */
00035 
00036 //----------------------------------------------------------------------------//
00037 
00043 //----------------------------------------------------------------------------//
00044 
00045 #ifndef _INCLUDED_Field3D_Curve_H_
00046 #define _INCLUDED_Field3D_Curve_H_
00047 
00048 //----------------------------------------------------------------------------//
00049 
00050 #include <algorithm>
00051 #include <utility>
00052 #include <vector>
00053 
00054 #include <boost/lexical_cast.hpp>
00055 
00056 #include <OpenEXR/ImathFun.h>
00057 #include <OpenEXR/ImathMatrix.h>
00058 
00059 //----------------------------------------------------------------------------//
00060 
00061 #include "ns.h"
00062 
00063 FIELD3D_NAMESPACE_OPEN
00064 
00065 //----------------------------------------------------------------------------//
00066 // Curve
00067 //----------------------------------------------------------------------------//
00068 
00075 //----------------------------------------------------------------------------//
00076 
00077 template <typename T>
00078 class Curve
00079 {
00080 public:
00081 
00082   // Typedefs ------------------------------------------------------------------
00083 
00084   typedef std::pair<float, T> Sample;
00085   typedef std::vector<Sample> SampleVec;
00086 
00087   // Main methods --------------------------------------------------------------
00088 
00092   void addSample(const float t, const T &value);
00093 
00096   T linear(const float t) const;
00097 
00099   size_t numSamples() const
00100   { return m_samples.size(); }
00101 
00103   const SampleVec& samples() const
00104   { return m_samples; }
00105 
00107   void clear() 
00108   { SampleVec().swap(m_samples); }
00109 
00110 private:
00111   
00112   // Structs -------------------------------------------------------------------
00113 
00115   struct CheckTGreaterThan : 
00116     public std::unary_function<std::pair<float, T>, bool>
00117   {
00118     CheckTGreaterThan(float match)
00119       : m_match(match)
00120     { }
00121     bool operator()(std::pair<float, T> test)
00122     {
00123       return test.first > m_match;
00124     }
00125   private:
00126     float m_match;
00127   };
00128 
00130   struct CheckTEqual : 
00131     public std::unary_function<std::pair<float, T>, bool>
00132   {
00133     CheckTEqual(float match)
00134       : m_match(match)
00135     { }
00136     bool operator()(std::pair<float, T> test)
00137     {
00138       return test.first == m_match;
00139     }
00140   private:
00141     float m_match;
00142   };
00143 
00144   // Utility methods -----------------------------------------------------------
00145 
00150   T defaultReturnValue() const
00151   { return T(0); }
00152 
00156   T lerp(const Sample &lower, const Sample &upper, const float t) const
00157   { return Imath::lerp(lower.second, upper.second, t); }
00158 
00159   // Private data members ------------------------------------------------------
00160 
00163   SampleVec m_samples;
00164 
00165 };
00166 
00167 //----------------------------------------------------------------------------//
00168 // Template implementations
00169 //----------------------------------------------------------------------------//
00170 
00171 template <typename T>
00172 void Curve<T>::addSample(const float t, const T &value)
00173 {
00174   using namespace std;
00175   // Check that sample time is not already in curve
00176   typename SampleVec::iterator i =                                        
00177     find_if(m_samples.begin(), m_samples.end(), CheckTEqual(t));
00178   if (i != m_samples.end()) {
00179     // Sample position already exists, so we replace it
00180     i->second = value;
00181     return;
00182   }
00183   // Find the first sample location that is greater than the interpolation
00184   // position                                                             
00185   i = find_if(m_samples.begin(), m_samples.end(), CheckTGreaterThan(t));
00186   // If we get something other than end() back then we insert the new     
00187   // sample before that. If there wasn't a larger value we add this sample
00188   // to the end of the vector.
00189   if (i != m_samples.end()) {
00190     m_samples.insert(i, make_pair(t, value));
00191   } else {
00192     m_samples.push_back(make_pair(t, value));
00193   }
00194 }
00195 
00196 //----------------------------------------------------------------------------//
00197 
00198 template <typename T>
00199 T Curve<T>::linear(const float t) const
00200 {
00201   using namespace std;
00202   // If there are no samples, return zero
00203   if (m_samples.size() == 0) {
00204     return defaultReturnValue();
00205   }
00206   // Find the first sample location that is greater than the interpolation
00207   // position
00208   typename SampleVec::const_iterator i =
00209     find_if(m_samples.begin(), m_samples.end(), CheckTGreaterThan(t));
00210   // If we get end() back then there was no sample larger, so we return the
00211   // last value. If we got the first value then there is only one value and
00212   // we return that.
00213   if (i == m_samples.end()) {
00214     return m_samples.back().second;
00215   } else if (i == m_samples.begin()) {
00216     return m_samples.front().second;
00217   }
00218   // Interpolate between the nearest two samples.
00219   const Sample &upper = *i;
00220   const Sample &lower = *(--i);
00221   const float interpT = Imath::lerpfactor(t, lower.first, upper.first);
00222   return lerp(lower, upper, interpT);
00223 }
00224 
00225 //----------------------------------------------------------------------------//
00226 // Template specializations
00227 //----------------------------------------------------------------------------//
00228 
00229 template <>
00230 inline Imath::Matrix44<float> 
00231 Curve<Imath::Matrix44<float> >::defaultReturnValue() const
00232 { 
00233   Imath::Matrix44<float> identity;
00234   identity.makeIdentity();
00235   return identity;
00236 }
00237 
00238 //----------------------------------------------------------------------------//
00239 
00240 template <>
00241 inline Imath::Matrix44<double> 
00242 Curve<Imath::Matrix44<double> >::defaultReturnValue() const
00243 { 
00244   Imath::Matrix44<double> identity;
00245   identity.makeIdentity();
00246   return identity;
00247 }
00248 
00249 //----------------------------------------------------------------------------//
00250 
00251 FIELD3D_NAMESPACE_HEADER_CLOSE
00252 
00253 //----------------------------------------------------------------------------//
00254 
00255 #endif // Include guard