#ifndef __JMATH__JMATH__ #define __JMATH__JMATH__ #include #include #include "JLang/JNullType.hh" #include "JLang/JClass.hh" #include "JLang/JBool.hh" #include "JLang/JVectorize.hh" #include "JLang/JException.hh" #include "JMath/JZero.hh" /** * \file * * Base class for data structures with artithmetic capabilities. * \author mdejong */ namespace JMATH {} namespace JPP { using namespace JMATH; } namespace JGEOMETRY3D { class JQuaternion3D; } namespace JMATH { using JLANG::JNullType; using JLANG::array_type; using JLANG::JDivisionByZero; /** * Power \f$ x^{y} \f$. * * \param x value * \param y power * \return result */ template inline T pow(const T& x, const double y); /** * Auxiliary class to hide data type specific methods. */ struct JMath_t { /** * Friend declaration of global method. */ template friend T JMATH::pow(const T&, const double y); private: /** * Power \f$ x^{y} \f$. * This method corresponds to primitive data types. * * \param x value * \param y power * \param option true * \return result */ template static inline T pow(const T& x, const double y, const JLANG::JBool option) { return std::pow(x, y); } /** * Power \f$ x^{y} \f$. * * This method corresponds to non-primitive data types. * * \param x value * \param y power * \param option false * \return result */ template static inline T pow(const T& x, const double y, const JLANG::JBool option) { return T(x).pow(y); } }; /** * Power \f$ x^{y} \f$. * * \param x value * \param y power * \return result */ template inline T pow(const T& x, const double y) { using namespace JPP; return JMath_t::pow(x, y, JBool::is_primitive>()); } /** * Auxiliary base class for aritmetic operations of derived class types. */ template struct JMath; /** * Template base class for data structures with arithmetic capabilities. * * This class provides for the operators - += -= *= /= + - * / .\n * To this end, the template parameter should privide for the corresponding member methods: *
   *       T& negate();
   *       T& add(const T& object);
   *       T& sub(const T& object);
   *       T& mul(const double factor);
   *       T& div(const double factor);
   * 
* * This class also provides for the object multiplication operators *= *.\n * To this end, the template parameter should then also provide for the member method: *
   *       T& mul(const T&, const T&);
   * 
* * This class adds interpolation functionality.\n * This class uses in-class friend operators (see Barton-Nackman trick). */ template struct JMath { /** * Affirm operator. * * \param object this object * \return affirmed object */ friend T operator+(const T& object) { return T(object); } /** * Negate operator. * * \param object this object * \return negated object */ friend T operator-(const T& object) { return T(object).negate(); } /** * Add object. * * \param object this object * \param value value * \return this object */ friend T& operator+=(T& object, const T& value) { return object.add(value); } /** * Subtract object. * * \param object this object * \param value value * \return this object */ friend T& operator-=(T& object, const T& value) { return object.sub(value); } /** * Scale object. * * \param object this object * \param factor factor * \return this object */ friend T& operator*=(T& object, const double factor) { return object.mul(factor); } /** * Scale object. * * \param object this object * \param factor factor * \return this object */ friend T& operator/=(T& object, const double factor) { return object.div(factor); } /** * Add objects. * * \param first first object * \param second second object * \return result object */ friend T operator+(const T& first, const T& second) { return T(first).add(second); } /** * Subtract objects. * * \param first first object * \param second second object * \return result object */ friend T operator-(const T& first, const T& second) { return T(first).sub(second); } /** * Scale object. * * \param object object * \param factor factor * \return object */ friend T operator*(const T& object, const double factor) { return T(object).mul(factor); } /** * Scale object. * * \param factor factor * \param object object * \return object */ friend T operator*(const double factor, const T& object) { return T(object).mul(factor); } /** * Scale object. * * \param object object * \param factor factor * \return object */ friend T operator/(const T& object, const double factor) { return T(object).div(factor); } /** * Multiply with object. * * \param object object * \return result object */ T& mul(const T& object) { return (static_cast(*this) = T().mul(static_cast(*this), object)); } /** * Multiply with object. * * \param first first object * \param second second object * \return result object */ friend T& operator*=(T& first, const T& second) { return static_cast&>(first).mul(second); } /** * Multiply objects. * * \param first first object * \param second second object * \return calculator */ friend T operator*(const T& first, const T& second) { return T().mul(first, second); } /** * Interpolation between objects. * The result is equal to *this = (1 - alpha) * (*this) + (alpha) * (object). * * \param object object * \param alpha interpolation factor [0, 1] * \return this object */ T& interpolate(const T& object, const double alpha) { static_cast(this)->mul(1.0 - alpha); static_cast(this)->add(T(object).mul(alpha)); return static_cast(*this); } }; /** * Specialisation of JMath for two data types. * * This class provides for the object multiplication operators *= *. * The template parameter should then have the member method: *
   *       JFirst_t& mul(const JFirst_t&, const JSecond_t&);
   * 
* where JFirst_t and JSecond_t refer to the first and second template parameter, respectively. * * This class uses in-class friend operators (see Barton-Nackman trick). */ template struct JMath { /** * Multiply with object. * * \param object object * \return result object */ JFirst_t& mul(const JSecond_t& object) { return static_cast(*this) = JFirst_t().mul(static_cast(*this), object); } /** * Multiply with object. * * \param first first object * \param second second object * \return result object */ friend JFirst_t& operator*=(JFirst_t& first, const JSecond_t& second) { return first.mul(second); } /** * Multiply objects. * * \param first first object * \param second second object * \return result object */ friend JFirst_t operator*(const JFirst_t& first, const JSecond_t& second) { return JFirst_t(first).mul(second); } }; /** * Interpolation between objects. * The result is equal to result = (1 - alpha) * (first) + (alpha) * (second). * * \param first first object * \param second second object * \param alpha interpolation factor [0, 1] * \return result */ template inline T interpolate(const T& first, const T& second, const double alpha) { return T(first).interpolate(second, alpha); } /** * Auxiliary class to determine average of set of values. */ template struct JAverage { /** * Default constructor. */ JAverage() : value (getZero()), weight(0.0) {} /** * Constructor. * * \param __begin begin of data * \param __end end of data */ template JAverage(T __begin, T __end) : value (getZero()), weight(0.0) { for (T i = __begin; i != __end; ++i) { value += (*i); weight += 1.0; } } /** * Reset. */ void reset() { this->value = getZero(); this->weight = 0.0; } /** * Type conversion operator. * * \return value */ operator JValue_t () const { if (weight != 0.0) return value * (1.0 / weight); else THROW(JDivisionByZero, "Invalid weight."); } /** * Put value. * * \param value value * \param w weight */ void put(const JValue_t& value, const double w = 1.0) { this->value += value; this->weight += w; } private: JValue_t value; double weight; }; /** * Template definition so that compiler error is generated if implementation is missing (see JEigen3D.hh). */ template<> struct JAverage; /** * Get average. * * \param __begin begin of data * \param __end end of data * \return average value */ template typename std::iterator_traits::value_type getAverage(T __begin, T __end) { typedef typename std::iterator_traits::value_type value_type; return JAverage(__begin, __end); } /** * Get average. * * \param array c-array of values * \return average value */ template inline JValue_t getAverage(const JValue_t (&array)[N]) { typedef JValue_t value_type; return JAverage((const value_type*) array, (const value_type*) array + N); } /** * Get average. * * \param buffer input data * \return average value */ template JElement_t getAverage(const array_type& buffer) { return JAverage(buffer.begin(), buffer.end()); } /** * Get average. * * \param __begin begin of data * \param __end end of data * \param value default value * \return average value */ template typename std::iterator_traits::value_type getAverage(T __begin, T __end, typename std::iterator_traits::value_type value) { try { return getAverage(__begin, __end); } catch(const std::exception&) { return value; } } /** * Get average. * * \param array c-array of values * \param value default value * \return average value */ template inline JValue_t getAverage(const JValue_t (&array)[N], typename JLANG::JClass::argument_type value) { try { return getAverage(array); } catch(const std::exception&) { return value; } } /** * Get average. * * \param buffer input data * \param value default value * \return average value */ template JElement_t getAverage(const array_type& buffer, typename JLANG::JClass::argument_type value) { try { return getAverage(buffer); } catch(const std::exception&) { return value; } } } #endif