vec3.h File Reference

Go to the documentation of this file. Source: include/ffw/graphics/vec3.h

/* This file is part of FineFramework project */
#ifndef FFW_VEC3
#define FFW_VEC3

#include "quaternion.h"
#include <limits>

namespace ffw {
    template <class T> struct Vec3 {
    public:
        T x;
        T y;
        T z;
        inline Vec3() {
            x = 0;
            y = 0;
            z = 0;
        }

        inline Vec3(T compx, T compy, T compz) {
            x = compx;
            y = compy;
            z = compz;
        }

        inline Vec3(T val) {
            x = val;
            y = val;
            z = val;
        }

        inline Vec3(const Vec3<T>& vec) {
            x = vec.x;
            y = vec.y;
            z = vec.z;
        }

        inline Vec3(const std::initializer_list<T>& list) {
            if (list.size() != 3) {
                x = 0;
                y = 0;
                z = 0;
                return;
            }
            x = *(list.begin());
            y = *(list.begin() + 1);
            z = *(list.begin() + 2);
        }

        inline void set(T compx, T compy, T compz) {
            x = compx;
            y = compy;
            z = compz;
        }

        inline void set(T val) {
            x = val;
            y = val;
            z = val;
        }

        inline void set(const Vec3<T>& vec) {
            x = vec.x;
            y = vec.y;
            z = vec.z;
        }

        inline void set(const std::initializer_list<T>& list) {
            if (list.size() != 3)return;
            x = *(list.begin());
            y = *(list.begin() + 1);
            z = *(list.begin() + 2);
        }

        inline ffw::Vec3<T>  operator - () const {
            return Vec3<T>(-x, -y, -z);
        }

        inline ffw::Vec3<T>& operator =  (const Vec3<T>& vec) {
            x = vec.x;
            y = vec.y;
            z = vec.z;
            return *this;
        }

        inline ffw::Vec3<T>  operator +  (const Vec3<T>& vec) const {
            return Vec3<T>(x + vec.x, y + vec.y, z + vec.z);
        }

        inline ffw::Vec3<T>& operator += (const Vec3<T>& vec) {
            x += vec.x;
            y += vec.y;
            z += vec.z;
            return *this;
        }

        inline ffw::Vec3<T>  operator -  (const Vec3<T>& vec) const {
            return Vec3<T>(x - vec.x, y - vec.y, z - vec.z);
        }

        inline ffw::Vec3<T>& operator -= (const Vec3<T>& vec) {
            x -= vec.x;
            y -= vec.y;
            z -= vec.z;
            return *this;
        }

        inline ffw::Vec3<T>  operator /  (const Vec3<T>& vec) const {
            return Vec3<T>(x / vec.x, y / vec.y, z / vec.z);
        }

        inline ffw::Vec3<T>& operator /= (const Vec3<T>& vec) {
            x /= vec.x;
            y /= vec.y;
            z /= vec.z;
            return *this;
        }

        inline ffw::Vec3<T>  operator *  (const Vec3<T>& vec) const {
            return Vec3<T>(x * vec.x, y * vec.y, z * vec.z);
        }

        inline ffw::Vec3<T>& operator *= (const Vec3<T>& vec) {
            x *= vec.x;
            y *= vec.y;
            z *= vec.z;
            return *this;
        }

        inline ffw::Vec3<T>& operator =  (const T& val) {
            x = val;
            y = val;
            z = val;
            return *this;
        }

        inline ffw::Vec3<T>  operator +  (const T& val) const {
            return Vec3<T>(x + val, y + val, z + val);
        }

        inline ffw::Vec3<T>& operator += (const T& val) {
            x += val;
            y += val;
            z += val;
            return *this;
        }

        inline ffw::Vec3<T>  operator -  (const T& val) const {
            return Vec3<T>(x - val, y - val, z - val);
        }

        inline ffw::Vec3<T>& operator -= (const T& val) {
            x -= val;
            y -= val;
            z -= val;
            return *this;
        }

        inline ffw::Vec3<T>  operator /  (const T& val) const {
            return Vec3<T>(x / val, y / val, z / val);
        }

        inline ffw::Vec3<T>& operator /= (const T& val) {
            x /= val;
            y /= val;
            z /= val;
            return *this;
        }

        inline ffw::Vec3<T>  operator *  (const T& val) const {
            return Vec3<T>(x * val, y * val, z * val);
        }

        inline ffw::Vec3<T>& operator *= (const T& val) {
            x *= val;
            y *= val;
            z *= val;
            return *this;
        }

        inline bool operator != (const Vec3<T>& vec) const {
            return !(*this == vec);
        }

        inline bool operator == (const Vec3<T>& vec) const {
            return (x == vec.x && y == vec.y && z == vec.z);
        }

        inline ffw::Vec3<T>& rotateByAxis(double deg, Vec3<T> axis) {
            return rotateByAxisRad(deg * DEG_TO_RAD, axis);
        }

        inline ffw::Vec3<T>& rotateByAxisRad(double rad, Vec3<T> axis) {
            const auto sina = std::sin(rad);
            const auto cosa = std::cos(rad);
            const auto cosb = 1.0f - cosa;
            auto v = *this;
            x = static_cast<T>(v.x*(axis.x*axis.x*cosb + cosa) + v.y*(axis.x*axis.y*cosb - axis.z*sina) + v.z*(axis.x*axis.z*cosb + axis.y*sina));
            y = static_cast<T>(v.x*(axis.y*axis.x*cosb + axis.z*sina) + v.y*(axis.y*axis.y*cosb + cosa) + v.z*(axis.y*axis.z*cosb - axis.x*sina));
            z = static_cast<T>(v.x*(axis.z*axis.x*cosb - axis.y*sina) + v.y*(axis.z*axis.y*cosb + axis.x*sina) + v.z*(axis.z*axis.z*cosb + cosa));
            return *this;
        }

        inline ffw::Vec3<T>& rotateX(double deg) {
            T vy = y;
            T vz = z;
            //x = vx;
            y = static_cast<T>(vy*std::cos(deg*DEG_TO_RAD) - vz*std::sin(deg*DEG_TO_RAD));
            z = static_cast<T>(vy*std::sin(deg*DEG_TO_RAD) + vz*std::cos(deg*DEG_TO_RAD));
            return *this;
        }

        inline ffw::Vec3<T>& rotateY(double deg) {
            T vx = x;
            T vz = z;
            x = static_cast<T>(vx*std::cos(deg*DEG_TO_RAD) + vz*std::sin(deg*DEG_TO_RAD));
            //y = vy;
            z = static_cast<T>(vx*-std::sin(deg*DEG_TO_RAD) + vz*std::cos(deg*DEG_TO_RAD));
            return *this;
        }

        inline ffw::Vec3<T>& rotateZ(double deg) {
            T vx = x;
            T vy = y;
            x = static_cast<T>(vx*std::cos(deg*DEG_TO_RAD) - vy*std::sin(deg*DEG_TO_RAD));
            y = static_cast<T>(vx*std::sin(deg*DEG_TO_RAD) + vy*std::cos(deg*DEG_TO_RAD));
            //z = vz;
            return *this;
        }

        inline ffw::Vec3<T>& rotateXRad(double rad) {
            T vy = y;
            T vz = z;
            //x = vx;
            y = static_cast<T>(vy*std::cos(rad) - vz*std::sin(rad));
            z = static_cast<T>(vy*std::sin(rad) + vz*std::cos(rad));
            return *this;
        }

        inline ffw::Vec3<T>& rotateYRad(double rad) {
            T vx = x;
            T vz = z;
            x = static_cast<T>(vx*std::cos(rad) + vz*std::sin(rad));
            //y = vy;
            z = static_cast<T>(vx*-std::sin(rad) + vz*std::cos(rad));
            return *this;
        }

        inline ffw::Vec3<T>& rotateZRad(double rad) {
            T vx = x;
            T vy = y;
            x = static_cast<T>(vx*std::cos(rad) - vy*std::sin(rad));
            y = static_cast<T>(vx*std::sin(rad) + vy*std::cos(rad));
            //z = vz;
            return *this;
        }

        template<class S>
        inline ffw::Vec3<T>& rotateByQuaternion(const ffw::Quaternion<S>& quat) {
            ffw::Vec3<T> qvc;
            qvc.x = static_cast<T>(quat.y*z - quat.z*y);
            qvc.y = static_cast<T>(quat.z*x - quat.x*z);
            qvc.z = static_cast<T>(quat.x*y - quat.y*x);
            ffw::Vec3<T> qvcc;
            qvcc.x = static_cast<T>(quat.y*qvc.z - quat.z*qvc.y);
            qvcc.y = static_cast<T>(quat.z*qvc.x - quat.x*qvc.z);
            qvcc.z = static_cast<T>(quat.x*qvc.y - quat.y*qvc.x);
            qvc = static_cast<T>(qvc * (2.0 * quat.w));
            qvcc = static_cast<T>(qvcc * 2.0);
            *this += qvc + qvcc;
            return *this;
        }

        inline ffw::Vec3<T>& normalize() {
            double l = sqrt(x*x + y*y + z*z);
            if (l > 0) {
                x = static_cast<T>(x / l);
                y = static_cast<T>(y / l);
                z = static_cast<T>(z / l);
            }
            return *this;
        }

        inline ffw::Vec3<T>& scale(T val) {
            x = x*val;
            y = y*val;
            z = z*val;
            return *this;
        }

        inline double length() const {
            return sqrt(static_cast<double>(x*x + y*y + z*z));
        }

        inline float lengthf() const {
            return sqrtf(static_cast<float>(x*x + y*y + z*z));
        }

        inline T lengthSqrd() const {
            return (x*x + y*y + z*z);
        }
        
        T& operator [] (size_t i){
            return ((T*)&x)[i];
        }

        const T& operator [] (size_t i) const  {
            return ((T*)&x)[i];
        }

        template <class S>
        inline operator ffw::Vec3<S>() const {
            return ffw::Vec3<S>((S)x, (S)y, (S)z);
        }

        inline Vec3<T> round() const {
            return Vec3<T>(std::round(x), std::round(y), std::round(z));
        }

        inline Vec3<T> floor() const {
            return Vec3<T>(std::floor(x), std::floor(y), std::floor(z));
        }

        inline Vec3<T> ceil() const {
            return Vec3<T>(std::ceil(x), std::ceil(y), std::ceil(z));
        }
    };
    typedef Vec3<float> Vec3f;
    typedef Vec3<int> Vec3i;
    typedef Vec3<short> Vec3s;
    typedef Vec3<long long> Vec3ll;
    typedef Vec3<double> Vec3d;
    template <class T>
    inline T dot(const ffw::Vec3<T>& v1, const ffw::Vec3<T>& v2) {
        return (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
    }
    template <class T>
    inline ffw::Vec3<T> cross(const ffw::Vec3<T>& v1, const ffw::Vec3<T>& v2) {
        ffw::Vec3<T> product;
        product.x = v1.y*v2.z - v1.z*v2.y;
        product.y = v1.z*v2.x - v1.x*v2.z;
        product.z = v1.x*v2.y - v1.y*v2.x;
        return product;
    }
    template <class T>
    inline T distance(const Vec3<T>& v1, const Vec3<T>& v2) {
        auto v = v2 - v1;
        return static_cast<T>(v.length());
    }
    template <class T>
    inline Vec3<T> middle(const Vec3<T>& v1, const Vec3<T>& v2) {
        auto v = (v2 - v1) / 2.0;
        return v1 + v;
    }
    template <class T>
    inline ffw::Vec3<T> normalize(const Vec3<T>& vec) {
        auto copy = vec;
        copy.normalize();
        return copy;
    }
    template <class T>
    inline double angle(const ffw::Vec3<T>& v1, const ffw::Vec3<T>& v2) {
        const auto dot = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
        const auto V1Length = sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z);
        const auto V2Length = sqrt(v2.x*v2.x + v2.y*v2.y + v2.z*v2.z);
        return static_cast<double>(acos(dot / (V1Length*V2Length))*RAD_TO_DEG);
    }
    template <class T>
    inline double angleRad(const ffw::Vec3<T>& v1, const ffw::Vec3<T>& v2) {
        const auto dot = (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
        const auto V1Length = sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z);
        const auto V2Length = sqrt(v2.x*v2.x + v2.y*v2.y + v2.z*v2.z);
        return static_cast<double>(acos(dot / (V1Length*V2Length)));
    }
    template <class T>
    inline std::ostream& operator << (std::ostream& os, const ffw::Vec3<T>& vec) {
        os << vec.x << ", " << vec.y << ", " << vec.z;
        return os;
    }
};
namespace ffw {
    template <>
    inline bool Vec3<float>::operator == (const Vec3<float>& vec) const {
        if (fabs(x - vec.x) > std::numeric_limits<float>::epsilon())return false;
        if (fabs(y - vec.y) > std::numeric_limits<float>::epsilon())return false;
        if (fabs(z - vec.z) > std::numeric_limits<float>::epsilon())return false;
        return true;
    }

    template <>
    inline bool Vec3<double>::operator == (const Vec3<double>& vec) const {
        if (fabs(x - vec.x) > std::numeric_limits<double>::epsilon())return false;
        if (fabs(y - vec.y) > std::numeric_limits<double>::epsilon())return false;
        if (fabs(z - vec.z) > std::numeric_limits<double>::epsilon())return false;
        return true;
    }
};
#endif