<泛> C++3D數學庫設計詳解 向量篇

// 注:本內容爲做者原創,禁止在其餘網站複述內容以及用於商業盈利,如需引用,請標明出處:http://www.cnblogs.com/lv_anchoret/html

 

Prefaceios

  爲了支持光線追蹤的學習,決定寫一個3D泛型數學庫。express

  我採用的是windows平臺以及C++Template技術windows

  

  個人庫文件組織目錄以下ide

  --lvgm函數

  ----test學習

  ------testVec.cpp
測試

  ----type_vec網站

  ------lv_vec2.hthis

  ------lv_vec3.h

  ------type_vec.h

  ------vec_inout.h

  ----lv_precision.h

  ----lvgm.h

Ready

  這一篇,須要您瞭解C++Template的基本語法

      須要您瞭解向量的運算

  該向量庫文件解釋:

      二維向量模板類

      三維向量模板類

      數據精度設定

      本庫提供的向量相關的默認輸出形式設置文件

  該向量庫文件暫時沒有四元組lv_vec4,我將在以後添加並單獨寫一篇進行陳述

  該向量庫能爲您提供的功能:

      對向量內部數據方便自由地調取和設定

      向量的正負

      向量的加減乘除

      向量的自增自減

      向量的索引

      向量判等

      向量的賦值以及複合運算賦值

      向量的範數

      向量的範數平方

      向量的自身單位化

      返回該向量的高精度單位化向量

      向量的內積和外積運算(·、×)

      向量判空

Design

  因爲二維和三維的設計相仿,故此處以三維爲例進行描述

<1>類型相關

本類中公開定義數據值類型爲模板參T,範數精度類型爲經外部宏設定的類型——precision, 默認爲double

  設計問題:一開始咱們可能想到在模板類裏面利用宏控制數據存儲精度,但你可能會遇到問題。例如:

#    ifdef HIGHPRECISION        //set the high precision 
using norm_t = long double;

#    elif(defined LOWPRECISION)    //set the low preciion
using norm_t = float;

#    else
using norm_t = double;                //default precision

#    endif                        //set precision

假設我如今有一個int的三維向量,我想要返回一個實數精度(norm_t)的單位化向量,因而咱們寫了一個成員函數vec3<norm_t> ret_unit()const,咱們在主函數中須要建立一個vec3去接收ret_unit的返回值

那麼,咱們兩手一攤,迫不得已你可能這樣作:

    vec3<??> normal = intV.ret_unit();

你可能作不到,??多是vec3::norm_t 嗎,顯然不是,vec3是一個模板,只能先將vec3<T>中的T特化。忽然以爲,模板類中公開公佈了精度類型norm_t,可是卻用不上??

  解決方案

綜合考量到其餘類可能也須要精度設定,因此乾脆把這設置部分代碼單獨出來,而後將norm_t 更名爲precision,因而問題就解決了

模板類中只須要提早預處理precision文件便可進行以下簡單定義:

        using norm_t = precision;

而主函數中也方便多了

    vec3<precision> normal = intV.ret_unit();

 

<2>參數類型

我看過glm數學庫的源碼有一類函數是這麼實現的

template <typename T, precision P>
template <typename U>
    GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator+=(tvec3<U, P> const & v)
    {
        this->x += static_cast<T>(v.x);
        this->y += static_cast<T>(v.y);
        this->z += static_cast<T>(v.z);
        return *this;
    }

其實,意思就是它容許+=另一種類型的向量,而後我都強轉到自身類型T以後進行運算

  解決方案

我的有一拙見,我是下面這樣實現的,若是有什麼漏洞請郵件或者評論留言。

我能夠經過「重載」static_cast,或者進行一些操做使得vec3模板類可以實現相似內置整型之間的隱式自動類型轉換

那麼,我就不須要設定多個模板參在內部static_cast了。

好,咱們這麼作就能夠了:

        template<typename E>
        vec3(const vec3<E>& vec);        //static_cast

 

我在定義構造函數的時候支持其餘類型的vec3,哪裏須要vec3值傳遞,我就調用它。

 

<3>對數據進行方便自由的操做

不少數學庫貌似能夠直接v.x  v.y ,不少C-struct設計,但做爲C++黨,用C++語言寫代碼,要嚴格遵照數據隱藏,在不失語言原則的狀況下作到最方便。

1)不少庫支持 v.x = 3;

因而我定義:

        inline T& x()        { return _x; }

但我仍是重載了常量版本

        inline const T& x()const    { return _x; }

我但願對內部數據的修改的禁止令能夠經過參數來實現,好比:

template<typename T>
        inline vec3<T> operator/(const vec3<T>& v1, const vec3<T>& v2)
            {
            //the operator of / ,example 3 * 5 -> 15 , (1,2,3) * (2,3,4) -> (1/2,2/3,3/4)
            assert(v2.isnull());
            return operator/<T, T> (v1, v2);
            }

因此,我僅僅去重載v.x()的const版本,而不去禁止x()可修改

 

2)GLSL中還支持這種騷操做:v.rgb = v.gbr; or v.rg = v1.rg

我看了glm庫,它暫時沒有實現上述的操做支持

而GLSL庫我還沒研讀

因此,憑着自身粗淺的技術,只能實現獲取數據元組,而不能實現修改:

inline vec2<T> xy() { return vec2<T>{_x, _y}; }

 

<4>運算符設計

按照C++operator廣泛的設計原則,依舊是將單目和(複合)賦值運算符重載定義爲成員函數,而將雙目運算符定義爲友元或者外部函數,在本庫中採用STL設計原則,定義爲命名空間內的類外函數,爲了避免破壞C++類的封裝性

++、--等單目運算符請參見個人另一篇專門解說運算符重載的文章

此處,我只陳述與vec3類相關的設計細節

 

關於加減法,從數學角度講,一個向量加減一個標量是非法的,因此,本庫中不支持向量和標量的加減法,對於將每個元素加同一個值,請用偏移向量進行。


而乘法和除法則支持與標量進行運算,由於一個標量乘以一個向量,只是把向量長度延伸了,在數學上也是合法的。

 

除此以外,考慮到兩個vec3對象進行乘除法,若是this是int其餘是另一個是實數的話,我以爲仍是進行精度提高的好,因此有專門的重載,且應用了C++11的自動追蹤返回值類型技術

 

關於%以及%=,從數學角度講,實數並不支持%運算,只有integer纔有,而在圖形運算過程當中,大可能是實數,儘管本庫不全應用於圖形計算,可是%合法運算在工程項目中佔得也並很少,因此,若是須要,請自行將每個元素進行%,庫設計中不會由於極小部分的應用而使庫變得臃腫

 

向量範數以及單位化(標準化)

一個類型設計點:利用用戶設定精度類型norm_t定義範數的值類型以及返回的標準化向量模板參。

關於向量單位化,我寫了兩個,一個是自身單位化,此時遵循自己類型進行,意思就是int進行單位化仍然裏面的元素是int。

另外一個是返回單位化向量,這個時候是實數向量。

 

我想陳述的本庫相關的設計原則基本完畢。

 

TEST

測試效果:

△--****************** CONSTRUCTOR TEST ******************

 ******* ivec3 test *********
there are two ivec3s as intV{ 1,-2,3 } and intV2{ 1, }, the value of which as follows

[ 1, -2, 3 ]

[ 1, 0, 0 ]

there is a ivec2 : _2ivec{1,2}, and a integer 7 to construct a ivec3 as follows

the vec2 in front of the integer of 7: [ 1, 2, 7 ]

the number of 7 in front of vec2: [ 7, 1, 2 ]



 ******* fvec3 test **********

there is a fvec3 as fV{ 1.f,2.1f, }, the value of which as follows

[ 1, 2.1, 0 ]

there is a fvec2 : t{1.2f,}, and a value 3 to construct a ivec3 as follows

f2to3 : [ 1.2, 0, 3 ]

△--******************* FUNCTIONS TEST ********************

there is a ivec3{1, -2, 3}
the operator + or - of ivec3 as follows:

+ : [ 1, -2, 3 ]
- :[ -1, 2, -3 ]

-----------------------------------------------------------

there is a ivec3{1, -2, 3}

++ivec3:        the val of expression:[ 2, -1, 4 ]      the val of ivec3:[ 2, -1, 4 ]

ivec3++:        the val of expression:[ 1, -2, 3 ]      the val of ivec3:[ 2, -1, 4 ]

the operator of -- is the same as above

-----------------------------------------------------------

the operator[] of ivec3 as follows:

the intV[2] is 4
-----------------------------------------------------------

there are two ivec3s as intV{ 1,-2,3 } and intV2{ 1, }, the value of which as follows

intV is not equ to intV2

the operator = such that: intV2 = intV; the result as follows:
intV2 is [ 2, -1, 4 ]
intV is equ to intV2


there are two ivec3s as intV{ 1,-2,3 } and intV2{ 1, }, the value of which as follows

the operator += such that: intV += intV2, the result of which as follows:

intV is: [ 3, -1, 4 ]

the operator -= such that: intV -= intV2, the result of which as follows:

intV is: [ 2, -1, 4 ]

the value of intV is to become the original value


there are two ivec3s as intV{ 1,-2,3 } and intV2{ 2,1,3 }, the value of which as follows

the operator *= such that: intV *= intV2, the result of which as follows:

intV is: [ 4, -1, 12 ]

the operator /= such that: intV /= intV2, the result of which as follows:

intV is: [ 2, -1, 4 ]

the value of intV is to become the original value

-----------------------------------------------------------

the operator *= (number)such that: intV *= 5, the result of which as follows:

intV is: [ 10, -5, 20 ]

the operator /= (number) such that: intV /= 5, the result of which as follows:

intV is: [ 2, -1, 4 ]

the value of intV is to become the original value

the operator + 、 -、 * 、/ (ivec3 or number) is the same as above

-----------------------------------------------------------

the operator* between ivec3 and fvec3 as follows:

there is a ivec3: intV{1,-2,3}, there is a fvec3: fV{1.1f,2.3f,3.8f}, and the result of ivec3*fvec3 as follows:

res is: [ 1.1, -4.6, 11.4 ]

the result of * is up to the higher precision of both

the operator* between ivec3 and float as follows:

there is a ivec3: intV{1,-2,3}, there is a float: 3.14, and the result of ivec3*3.14 as follows:

res2 is: [ 3, -6, 9 ]

the type of ivec3 * float is not fvec3 but ivec3, and the factor is just a factor that shouldn't change the vec's precision
if you need the result's type to become fvec3,you should use static_cast<fvec3>(intV) * float

res3 is: [ 3.14, -6.28, 9.42 ]

the operator/ between different type is the same as above

-----------------------------------------------------------

the normal() test as follows:

there is a ivec3: intV{1,-2,3}

the Norm of intV is: 3.74166

there is a fvec3: fV{ 1.1, 2.3, 3.5}

the Norm of fV is: 4.57602

-----------------------------------------------------------

there is a ivec3: intV{0, 4, 3}

the unitization of intV is: [ 0, 0.8, 0.6 ]

-----------------------------------------------------------

there is a ivec3: intV{1,-2,3}, there is a fvec3: fV{1.1f,2.3f,3.8f}, and the result of ivec3·fvec3 as follows:

the dotval is: 7.9

crossVec is: [ -14.5, -0.5, 4.5 ]
test result

 

#define LOWPRECISION        //開啓低精度
#define VEC3_OUT            //開啓vec3輸出

#include <lvgm\lvgm.h>
#define stds std::
#define enter stds endl << stds endl

using lvgm::ivec2;
using lvgm::ivec3;
using lvgm::fvec3;
using lvgm::fvec2;

int main()
{
    ivec3 intV{ 1,-2,3 }, intV2{ 1, }, null;
    //null.self_unitization();
    ivec3 b;
    ivec2 _2ivec{ 1,2 };
    fvec3 fV{ 1.f,2.1f, };
    stds cout << "△--****************** CONSTRUCTOR TEST ******************" << enter;
    stds cout << " ******* ivec3 test *********" << stds endl;
    stds cout << "there are two ivec3s as intV{ 1,-2,3 } and intV2{ 1, }, the value of which as follows" << enter;
    stds cout << intV << enter;
    stds cout << intV2 << enter;
    stds cout << "there is a ivec2 : _2ivec{1,2}, and a integer 7 to construct a ivec3 as follows" << enter;
    ivec3 _2to3{ _2ivec, 7 };
    stds cout << "the vec2 in front of the integer of 7: " << _2to3 << enter;
    _2to3 = ivec3{ 7, _2ivec };
    stds cout << "the number of 7 in front of vec2: " << _2to3 << enter << enter;

    stds cout << " ******* fvec3 test **********" << enter;
    stds cout << "there is a fvec3 as fV{ 1.f,2.1f, }, the value of which as follows" << enter;
    stds cout << fV << enter;
    stds cout << "there is a fvec2 : t{1.2f,}, and a value 3 to construct a ivec3 as follows" << enter;
    fvec2 t{ 1.2f };
    fvec3 f2to3{ t,3 };
    stds cout << "f2to3 : " << f2to3 << enter;

    stds cout << "△--******************* FUNCTIONS TEST ********************" << enter;
    stds cout << "there is a ivec3{1, -2, 3}" << stds endl;
    stds cout << "the operator + or - of ivec3 as follows:" << enter;
    intV = +intV;
    stds cout << "+ : " << intV << stds endl;
    intV = -intV;
    stds cout << "- :" << intV << enter;
    intV = -intV;
    stds cout << "-----------------------------------------------------------" << enter;

    stds cout << "there is a ivec3{1, -2, 3}" << enter;
    auto re = ++intV;
    stds cout << "++ivec3:    the val of expression:" << re << "\tthe val of ivec3:" << intV << enter;
    --intV;
    re = intV++;
    stds cout << "ivec3++:    the val of expression:" << re << "\tthe val of ivec3:" << intV << enter;
    stds cout << "the operator of -- is the same as above" << enter;
    stds cout << "-----------------------------------------------------------" << enter;

    stds cout << "the operator[] of ivec3 as follows:" << enter;
    stds cout << "the intV[2] is " << intV[2] << stds endl;
    //stds cout << "the intV[4] is " << intV[4] << stds endl;
    stds cout << "-----------------------------------------------------------" << enter;

    stds cout << "there are two ivec3s as intV{ 1,-2,3 } and intV2{ 1, }, the value of which as follows" << enter;
    if (intV != intV2)stds cout << "intV is not equ to intV2" << enter;
    stds cout << "the operator = such that: intV2 = intV; the result as follows:" << stds endl;
    intV2 = intV;
    stds cout << "intV2 is " << intV2 << stds endl;
    if (intV2 == intV)stds cout << "intV is equ to intV2" << enter;
    stds cout << stds endl << "there are two ivec3s as intV{ 1,-2,3 } and intV2{ 1, }, the value of which as follows" << enter;
    stds cout << "the operator += such that: intV += intV2, the result of which as follows:" << enter;
    intV2 = { 1, };
    intV += intV2;
    stds cout << "intV is: " << intV << enter;
    stds cout << "the operator -= such that: intV -= intV2, the result of which as follows:" << enter;
    intV -= intV2;
    stds cout << "intV is: " << intV << enter;
    stds cout << "the value of intV is to become the original value" << enter;
    stds cout << stds endl << "there are two ivec3s as intV{ 1,-2,3 } and intV2{ 2,1,3 }, the value of which as follows" << enter;
    stds cout << "the operator *= such that: intV *= intV2, the result of which as follows:" << enter;
    intV2 = { 2,1,3 };
    intV *= intV2;
    stds cout << "intV is: " << intV << enter;
    intV /= intV2;
    stds cout << "the operator /= such that: intV /= intV2, the result of which as follows:" << enter;
    stds cout << "intV is: " << intV << enter;
    stds cout << "the value of intV is to become the original value" << enter;

    stds cout << "-----------------------------------------------------------" << enter;

    stds cout << "the operator *= (number)such that: intV *= 5, the result of which as follows:" << enter;
    intV *= 5;
    stds cout << "intV is: " << intV << enter;
    stds cout << "the operator /= (number) such that: intV /= 5, the result of which as follows:" << enter;
    intV /= 5;
    stds cout << "intV is: " << intV << enter;
    stds cout << "the value of intV is to become the original value" << enter;
    stds cout << "the operator + 、 -、 * 、/ (ivec3 or number) is the same as above" << enter;
    stds cout << "-----------------------------------------------------------" << enter;

    stds cout << "the operator* between ivec3 and fvec3 as follows:" << enter;
    stds cout << "there is a ivec3: intV{1,-2,3}, there is a fvec3: fV{1.1f,2.3f,3.8f}, and the result of ivec3*fvec3 as follows:" << enter;
    intV = { 1,-2,3 };
    fV = { 1.1f,2.3f,3.8f };
    auto res = intV*fV;
    stds cout << "res is: " << res << enter;
    stds cout << "the result of * is up to the higher precision of both" << enter;

    stds cout << "the operator* between ivec3 and float as follows:" << enter;
    stds cout << "there is a ivec3: intV{1,-2,3}, there is a float: 3.14, and the result of ivec3*3.14 as follows:" << enter;
    intV = { 1,-2,3 };
    auto res2 = intV*3.14;
    stds cout << "res2 is: " << res2 << enter;
    stds cout << "the type of ivec3 * float is not fvec3 but ivec3, and the factor is just a factor that shouldn't change the vec's precision" << stds endl
        << "if you need the result's type to become fvec3,you should use static_cast<fvec3>(intV) * float" << enter;
    intV = { 1,-2,3 };
    auto res3 = (static_cast<fvec3>(intV))*3.14;
    stds cout << "res3 is: " << res3 << enter;
    stds cout << "the operator/ between different type is the same as above" << enter;
    stds cout << "-----------------------------------------------------------" << enter;

    stds cout << "the normal() test as follows: " << enter;
    stds cout << "there is a ivec3: intV{1,-2,3}" << enter;
    stds cout << "the Norm of intV is: " << intV.normal() << enter;
    stds cout << "there is a fvec3: fV{ 1.1, 2.3, 3.5}" << enter;
    stds cout << "the Norm of fV is: " << fV.normal() << enter;
    stds cout << "-----------------------------------------------------------" << enter;

    stds cout << "there is a ivec3: intV{0, 4, 3}" << enter;
    intV = { 0,4,3 };
    lvgm::vec3<lvgm::precision> normal = intV.ret_unitization();
    stds cout << "the unitization of intV is: " << normal << enter;
    stds cout << "-----------------------------------------------------------" << enter;

    stds cout << "there is a ivec3: intV{1,-2,3}, there is a fvec3: fV{1.1f,2.3f,3.8f}, and the result of ivec3·fvec3 as follows:" << enter;
    intV = { 1,-2,3 };
    fV = { 1.1f,2.3f,3.8f };
    lvgm::precision dotval = lvgm::dot(intV, fV);
    stds cout << "the dotval is: " << dotval << enter;
    auto crossVec = cross(intV, fV);
    stds cout << "crossVec is: " << crossVec << enter;
}
test code

 

庫文件代碼

/// lvgm.h

// -----------------------------------------------------
// [author]        lv
// [ time ]        2018.12 ~ 2018.12
// [brief ]        include all of the mymath's head files
// -----------------------------------------------------

#ifndef LVGM_H
#define LVGM_H

#include <lvgm\type_vec\type_vec.h>

#endif  //LVGM_H
lvgm.h

 

/// precision.h

// -----------------------------------------------------
// [author]        lv
// [ time ]        2018.12 ~ 2018.12
// [brief ]        control the precision of data
// -----------------------------------------------------



#ifndef LV_PRECISION_H
#define LV_PRECISION_H


namespace lvgm
{

#    ifdef HIGHPRECISION            //set the high precision 
using precision = long double;

#    elif(defined LOWPRECISION)    //set the low preciion
using precision = float;

#    else
using precision = double;        //default precision

#    endif                        //set precision


}    //namespace lvgm

#endif        //LV_PRECISION_H
precision.h

 

/// myVec2.h

// -----------------------------------------------------
// [author]        lv
// [ time ]        2018.12 ~ 2018.12
// [brief ]        the definition of two-dimensional vector 
// -----------------------------------------------------


#ifndef LV_VEC2_H
#define LV_VEC2_H


namespace lvgm
{

template<typename T>
    class vec2
        {
    public:
        using value_type = T;
        
        using norm_t = precision;

    public:

        template<typename E>
        vec2(const vec2<E>& vec);        //static_cast

        vec2(const T x = T(), const T y = T())noexcept;

        vec2(const vec2&);

        ~vec2() {  }

    public:
        //inline get function
        inline T& x()    { return _x; }

        inline T& y()    { return _y; }

        inline T& u()    { return _x; }

        inline T& v()    { return _y; }

        inline T& r()    { return _x; }

        inline T& g()    { return _y; }

        inline T& s()    { return _x; }

        inline T& t()    { return _y; }

        inline vec2 xy() { return vec2<T>{_x, _y}; }

        inline vec2 yx() { return vec2<T>{_y, _x}; }

        inline vec2 rg() { return vec2<T>{_x, _y}; }

        inline vec2 gr() { return vec2<T>{_y, _x}; }

        inline vec2 uv() { return vec2<T>{_x, _y}; }

        inline vec2 vu() { return vec2<T>{_y, _x}; }

        inline vec2 st() { return vec2<T>{_x, _y}; }

        inline vec2 ts() { return vec2<T>{_y, _x}; }

        inline const T& x()const    { return _x; }

        inline const T& y()const    { return _y; }

        inline const T& u()const    { return _x; }

        inline const T& v()const    { return _y; }

        inline const T& r()const    { return _x; }

        inline const T& g()const    { return _y; }

        inline const T& s()const    { return _x; }

        inline const T& t()const    { return _y; }

        //inline operator function
        inline const vec2& operator+()const;

        inline vec2 operator-()const;

        inline vec2& operator++();

        inline vec2& operator--();

        inline const vec2 operator++(int);

        inline const vec2 operator--(int);

        inline const T& operator[](const int index)const;

        inline T& operator[](const int index);

        inline vec2& operator=(const vec2& rhs);

        inline vec2& operator+=(const vec2& rhs);

        inline vec2& operator-=(const vec2& rhs);

        inline vec2& operator*=(const vec2& rhs);

        inline vec2& operator/=(const vec2& rhs);

        inline vec2& operator*=(const T factor);

        inline vec2& operator/=(const T factor);

    public:
        //return the Norm of vec2
        inline norm_t normal()const;

        inline norm_t squar()const;

        //let self become to the unit vector of vec_type
        inline void self_unitization();

        //return a non-integer three-dimensional unit vector [the type is norm_t]
        inline vec2<precision> ret_unitization()const;

        inline bool isnull()const;

    private:
        T _x, _y;

        };

//constructor functions

    template<typename T>
        vec2<T>::vec2(const T x,const T y)noexcept
            :_x(x)
            ,_y(y)
    {    }

    template<typename T>
        template<typename E>
        vec2<T>::vec2(const vec2<E>& rhs)
            :_x(static_cast<T>(rhs.x()))
            ,_y(static_cast<T>(rhs.y()))
    {    }

    template<typename T>
        vec2<T>::vec2(const vec2<T>& rhs)
            :_x(rhs._x)
            ,_y(rhs._y)
    {    }

// Binary operator functions [non-mem]

    template<typename T>
        inline vec2<T> operator+(const vec2<T>& v1, const vec2<T>& v2)
            {
            return vec2<T>(v1[0] + v2[0], v1[1] + v2[1]);
            }

    template<typename T>
        inline vec2<T> operator-(const vec2<T>& v1, const vec2<T>& v2)
            {
            //the operator of - ,example  (5,4) - (2,2) -> (3,2)  
            return v1 + (-v2);
            }

    template<typename A, typename B>
        inline auto operator*(const vec2<A>& v1, const vec2<B>& v2)
            {
            //the operator of * ,example  (1.1, 2.1) * (2, 3) -> (2.2, 6.3)
            using type = decltype(v1[0] * v2[0]);
            return vec2<type>((type)v1[0] * v2[0], (type)v1[1] * v2[1]);
            }

    template<typename T>
        inline vec2<T> operator*(const vec2<T>& v1, const vec2<T>& v2)
            {
            //the operator of * ,example (1,2) * (2,3) -> (2,6)
            return vec2<T>(v1[0] * v2[0], v1[1] * v2[1]);
            }

    template<typename T, typename E>
        inline vec2<T> operator*(const vec2<T>& v, const E factor)
            {
            return vec2<T>(v.x() * factor, v.y() * factor);
            }

    template<typename T, typename E>
        inline vec2<T> operator*(const E factor, const vec2<T>& v)
            {
            return vec2<T>(v.x() * factor, v.y() * factor);
            }

    template<typename A, typename B>
        inline auto operator/(const vec2<A>& v1, const vec2<B>& v2)
            {
            //the operator of / ,example  (1.1, 2.1) * (2, 3) -> (0.55, 0.7)
            assert(v2.isnull());
            using type = decltype(v1[0] / v2[0]);
            return vec2<type>((type)v1[0] / v2[0], (type)v1[1] / v2[1]);
            }
    
    template<typename T>
        inline vec2<T> operator/(const vec2<T>& v1, const vec2<T>& v2)
            {
            //the operator of / ,example 3 * 5 -> 15 , (1,2) * (2,3) -> (1/2,2/3)
            assert(v2.isnull());
            return operator/<T, T> (v1, v2);
            }

    template<typename T, typename E>
        inline vec2<T> operator/(const vec2<T>& v, const E factor)
            {
            assert(factor != 0 && factor != 0.);
            return vec2<T>(v.x() / factor, v.y() / factor);
            }

    template<typename T>
        inline bool operator==(const vec2<T>& v1, const vec2<T>& v2)
            {
            return v1.x() == v2.x() && v1.y() == v2.y();
            }

    template<typename T>
        inline bool operator!=(const vec2<T>& v1, const vec2<T>& v2)
            {
            return !(v1 == v2);
            }

// Unary operator functions [mem]

    template<typename T>
        inline const vec2<T>& vec2<T>::operator+() const
            {
            //the operator of + ,example 5 -> +5,  +(1,-2) -> (1,-2)
            return *this;
            }

    template<typename T>
        inline vec2<T> vec2<T>::operator-() const
            {
            //the operator of - ,example 5 -> -5,  -(1,-2) -> (-1,2)
            return vec2<T>(-_x, -_y);
            }

    template<typename T>
        inline vec2<T>& vec2<T>::operator++()
            {
            ++this->_x;
            ++this->_y;
            return *this;
            }

    template<typename T>
        inline const vec2<T> vec2<T>::operator++(int)
            {
            vec2<T>ori(*this);
            ++*this;
            return ori;
            }

    template<typename T>
        inline vec2<T>& vec2<T>::operator--()
            {
            --this->_x;
            --this->_y;
            return *this;
            }

    template<typename T>
        inline const vec2<T> vec2<T>::operator--(int)
            {
            vec2<T>ori(*this);
            --*this;
            return ori;
            }

    template<typename T>
        inline const T& vec2<T>::operator[](const int index)const
            {
            if (index == 0)return _x;
            else if (index == 1)return _y;
            else throw "the index is error";
            }

    template<typename T>
        inline T& vec2<T>::operator[](const int index)
            {
            if (index == 0)return _x;
            else if (index == 1)return _y;
            else throw "the index is error";
            }

// member functions

    template<typename T>
        inline vec2<T>& vec2<T>::operator=(const vec2<T>& rhs)
            {
            if (this != &rhs)
                {
                _x = rhs._x;
                _y = rhs._y;
                }
            return *this;
            }

    template<typename T>
        inline vec2<T>& vec2<T>::operator+=(const vec2& rhs)
            {
            this->_x += rhs._x;
            this->_y += rhs._y;
            return *this;
            }

    template<typename T>
        inline vec2<T>& vec2<T>::operator-=(const vec2& rhs)
            {
            return *this += (-rhs);
            }

    template<typename T>
        inline vec2<T>& vec2<T>::operator/=(const vec2<T>& rhs)
            {
            assert(!rhs.isnull());
            this->_x /= rhs._x;
            this->_y /= rhs._y;
            return *this;
            }

    template<typename T>
        inline vec2<T>& vec2<T>::operator*=(const vec2<T>& rhs)
            {
            this->_x *= rhs._x;
            this->_y *= rhs._y;
            return *this;
            }

    template<typename T>
        inline vec2<T>& vec2<T>::operator*=(const T factor)
            {
            this->_x *= factor;
            this->_y *= factor;
            return *this;
            }

    template<typename T>
        inline vec2<T>& vec2<T>::operator/=(const T factor)
            {
            assert(factor != 0);
            this->_x /= factor;
            this->_y /= factor;
            return *this;
            }


    template<typename T>
        inline typename vec2<T>::norm_t vec2<T>::normal()const
            {
            return sqrt(squar());
            }

    template<typename T>
        inline typename vec2<T>::norm_t vec2<T>::squar()const
            {
            return _x*_x + _y*_y;
            }

    template<typename T>
        inline void vec2<T>::self_unitization()
            {
            *this /= normal();
            }

    template<typename T>
        inline vec2<precision> vec2<T>::ret_unitization()const
            {
            norm_t div = normal();
            return vec2<norm_t>{ (norm_t)this->_x / div, (norm_t)this->_y / div, (norm_t)this->_z / div };
            }

    template<typename T, typename E>
        inline auto dot(const vec2<T>& v1, const vec2<E>& v2) //-> decltype(v1.x() * v2.x() + v1.y() * v2.y()
            {// x1 * x2 + y1 * y2
            return v1.x() * v2.x() + v1.y() * v2.y();
            }

    template<typename T, typename E>
        inline auto cross(const vec2<T> v1, const vec2<E>& v2)
            {// v1 × v2
            return vec2<decltype(v1[1] * v2[2] - v1[2] * v2[1])>
                (
                v1[0] * v2[1] - v1[1] * v2[0]
                );
            }

    template<typename T>
        inline bool vec2<T>::isnull()const
            {
            return *this == vec2<T>();
            }

}    //namespace lvgm


#endif    //LV_VEC2_H
lv_vec2.h

 

/// myVec3.h

// -----------------------------------------------------
// [author]        lv
// [ time ]        2018.12 ~ 2018.12
// [brief ]        the definition of Three-dimensional vector
// -----------------------------------------------------

#ifndef LV_VEC3_H
#define LV_VEC3_H

namespace lvgm
{

template<typename T>
    class vec3
        {
    public:
        using value_type = T;

        using norm_t = precision;

    public:

        template<typename E>
        vec3(const vec3<E>& vec);        //static_cast

        vec3(const T e1 = T(), const T e2 = T(), const T e3 = T())noexcept;

        explicit vec3(const vec2<T>& v2, const T e3 = T())noexcept;

        explicit vec3(const T e1, const vec2<T>& v)noexcept;

        explicit vec3(const vec3&);

        ~vec3() {  }

    public:

        inline T& x()        { return _x; }

        inline T& y()        { return _y; }

        inline T& z()        { return _z; }

        inline T& r()        { return _x; }

        inline T& g()        { return _y; }

        inline T& b()        { return _z; }

        inline vec2<T> xy() { return vec2<T>{_x, _y}; }

        inline vec2<T> yx()    { return vec2<T>{_y, _x}; }

        inline vec2<T> xz()    { return vec2<T>{_x, _z}; }

        inline vec2<T> zx()    { return vec2<T>{_z, _x}; }

        inline vec2<T> yz()    { return vec2<T>{_y, _z}; }

        inline vec2<T> zy()    { return vec2<T>{_z, _y}; }

        inline vec2<T> rg()    { return vec2<T>{_x, _y}; }

        inline vec2<T> gr()    { return vec2<T>{_y, _x}; }

        inline vec2<T> rb()    { return vec2<T>{_x, _z}; }

        inline vec2<T> br()    { return vec2<T>{_z, _x}; }

        inline vec2<T> gb()    { return vec2<T>{_y, _z}; }

        inline vec2<T> bg()    { return vec2<T>{_z, _y}; }

        inline vec3 rgb()    { return vec3{_x, _y, _z}; }

        inline vec3 rbg()    { return vec3{_x, _z, _y}; }
            
        inline vec3 gbr()    { return vec3{_y, _z, _x}; }

        inline vec3 grb()    { return vec3{_y, _x, _z}; }

        inline vec3 bgr()    { return vec3{_z, _y, _x}; }

        inline vec3 brg()    { return vec3{_z, _x, _y}; }

        inline const T& x()const    { return _x; }

        inline const T& y()const    { return _y; }

        inline const T& z()const    { return _z; }

        inline const T& r()const    { return _x; }

        inline const T& g()const    { return _y; }

        inline const T& b()const    { return _z; }

        //inline oprator function
        inline const vec3& operator+() const;

        inline vec3 operator-()const;

        inline vec3& operator++();

        inline vec3& operator--();

        inline const vec3 operator++(int);

        inline const vec3 operator--(int);

        inline const T& operator[](const int index)const;

        inline T& operator[](const int index);

        inline vec3& operator=(const vec3& rhs);

        inline vec3& operator+=(const vec3& rhs);

        inline vec3& operator-=(const vec3& rhs);

        inline vec3& operator*=(const vec3& rhs);

        inline vec3& operator/=(const vec3& rhs);

        inline vec3& operator*=(const T factor);

        inline vec3& operator/=(const T factor);
        
    public:
        //return the Norm of vec3
        inline norm_t normal()const;

        inline norm_t squar()const;

        //let self become to the unit vector of vec_type
        inline void self_unitization();

        //return a non-integer three-dimensional unit vector [the type is norm_t]
        inline vec3<precision> ret_unitization()const;

        inline bool isnull()const;

    private:
        T _x, _y, _z;

        };

//constructor functions

    template<typename T>
        template<typename E>
        vec3<T>::vec3(const vec3<E>& vec)
            :_x(static_cast<T>(vec.x()))
            ,_y(static_cast<T>(vec.y()))
            ,_z(static_cast<T>(vec.z()))
        {    }
    
    template<typename T>
        vec3<T>::vec3(const T e1, const T e2, const T e3)noexcept
            :_x{e1}
            ,_y{e2}
            ,_z{e3}
        {    }

    template<typename T>
        vec3<T>::vec3(const vec2<T>& v, const T e3)noexcept
            :_x(v.x())
            ,_y(v.y())
            ,_z(e3)
        {    }

    template<typename T>
        vec3<T>::vec3(const T e, const vec2<T>& v)noexcept
            :_x(e)
            ,_y(v.x())
            ,_z(v.y())
        {    }

    template<typename T>
        vec3<T>::vec3(const vec3<T>& rhs)
            :_x{rhs._x}
            ,_y{rhs._y}
            ,_z{rhs._z}
        {    }

// Binary operator functions [non-mem]
    template<typename T>
        vec3<T> operator+(const vec3<T>& v1, const vec3<T>& v2)
            {
            //the operator of + ,example  (5,4,3) + (2,-2,1) -> (7,2,4)  
            return vec3<T>(v1[0] + v2[0], v1[1] + v2[1], v1[2] + v2[2]);
            }

    template<typename T>
        inline vec3<T> operator-(const vec3<T>& v1, const vec3<T>& v2)
            {
            //the operator of - ,example  (5,4,3) - (2,2,1) -> (3,2,2)  
            return v1 + (-v2);
            }

    template<typename A, typename B>
        inline auto operator*(const vec3<A>& v1, const vec3<B>& v2)
            {
            //the operator of * ,example  (1.1, 2.1, 3.1) * (2, 3, 4) -> (2.2, 6.3, 12.4)
            using type = decltype(v1[0] * v2[0]);
            return vec3<type>((type)v1[0] * v2[0], (type)v1[1] * v2[1], (type)v1[2] * v2[2]);
            }

    template<typename T>
        inline vec3<T> operator*(const vec3<T>& v1, const vec3<T>& v2)
            {
            //the operator of * ,example 3 * 5 -> 15 , (1,2,3) * (2,3,4) -> (2,6,12)
            return vec3<T>(v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2]);
            }

    template<typename T, typename E>
        inline vec3<T> operator*(const vec3<T>& v, const E factor)
            {
            return vec3<T>(v.x() * factor, v.y() * factor, v.z() * factor);
            }

    template<typename T, typename E>
        inline vec3<T> operator*(const E factor, const vec3<T>& v)
            {
            return vec3<T>(v.x() * factor, v.y() * factor, v.z() * factor);
            }

    template<typename A, typename B>
        inline auto operator/(const vec3<A>& v1, const vec3<B>& v2)
            {
            //the operator of / ,example  (1.1, 2.1, 3.2) * (2, 3, 4) -> (0.55, 0.7, 0.8)
            assert(v2.isnull());
            using type = decltype(v1[0] / v2[0]);
            return vec3<type>((type)v1[0] / v2[0], (type)v1[1] / v2[1], (type)v1[2] / v2[2]);
            }
        
    template<typename T>
        inline vec3<T> operator/(const vec3<T>& v1, const vec3<T>& v2)
            {
            //the operator of / ,example 3 * 5 -> 15 , (1,2,3) * (2,3,4) -> (1/2,2/3,3/4)
            assert(v2.isnull());
            return operator/<T, T> (v1, v2);
            }

    template<typename T, typename E>
        inline vec3<T> operator/(const vec3<T>& v, const E factor)
            {
            assert(factor != 0 && factor != 0.);
            return vec3<T>(v.x() / factor, v.y() / factor, v.z() / factor);
            }

    template<typename T>
        inline bool operator==(const vec3<T>& v1, const vec3<T>& v2)
            {
            return v1.x() == v2.x() && v1.y() == v2.y() && v1.z() == v2.z();
            }

    template<typename T>
        inline bool operator!=(const vec3<T>& v1, vec3<T>& v2)
            {
            return !(v1 == v2);
            }

// Unary operator functions [mem]
    template<typename T>
        inline const vec3<T>& vec3<T>::operator+() const 
            {
            //the operator of + ,example 5 -> +5,  +(1,-2,3) -> (1,-2,3)
            return *this; 
            }

    template<typename T>
        inline vec3<T> vec3<T>::operator-() const
            {
            //the operator of - ,example 5 -> -5,  -(1,-2,3) -> (-1,2,-3)
            return vec3<T>(-_x, -_y, -_z);
            }

    template<typename T>
        inline vec3<T>& vec3<T>::operator++()
            {
            ++this->_x;
            ++this->_y;
            ++this->_z;
            return *this;
            }

    template<typename T>
        inline const vec3<T> vec3<T>::operator++(int)
            {
            vec3<T>ori(*this);
            ++*this;
            return ori;
            }

    template<typename T>
        inline vec3<T>& vec3<T>::operator--()
            {
            --this->_x;
            --this->_y;
            --this->_z;
            return *this;
            }

    template<typename T>
        inline const vec3<T> vec3<T>::operator--(int)
            {
            vec3<T>ori(*this);
            --*this;
            return ori;
            }

    template<typename T>
        inline const T& vec3<T>::operator[](const int index)const
            {
            if (index == 0)return _x;
            else if (index == 1)return _y;
            else if (index == 2)return _z;
            else throw "the index is error";
            }

    template<typename T>
        inline T& vec3<T>::operator[](const int index)
            {
            if (index == 0)return _x;
            else if (index == 1)return _y;
            else if (index == 2)return _z;
            else throw "the index is error";
            }

// member functions
    template<typename T>
        inline vec3<T>& vec3<T>::operator=(const vec3<T>& rhs)
            {
            if (this != &rhs)
                {
                _x = rhs._x;
                _y = rhs._y;
                _z = rhs._z;
                }
            return *this;
            }

    template<typename T>
        inline vec3<T>& vec3<T>::operator+=(const vec3& rhs)
            {
            this->_x += rhs._x;
            this->_y += rhs._y;
            this->_z += rhs._z;
            return *this;
            }

    template<typename T>
        inline vec3<T>& vec3<T>::operator-=(const vec3& rhs)
            {
            this->_x -= rhs._x;
            this->_y -= rhs._y;
            this->_z -= rhs._z;
            return *this;
            }

    template<typename T>
        inline vec3<T>& vec3<T>::operator/=(const vec3<T>& rhs)
            {
            assert(!rhs.isnull());
            this->_x /= rhs._x;
            this->_y /= rhs._y;
            this->_z /= rhs._z;
            return *this;
            }

    template<typename T>
        inline vec3<T>& vec3<T>::operator*=(const vec3<T>& rhs)
            {
            this->_x *= rhs._x;
            this->_y *= rhs._y;
            this->_z *= rhs._z;
            return *this;
            }

    template<typename T>
        inline vec3<T>& vec3<T>::operator*=(const T factor)
            {
            this->_x *= factor;
            this->_y *= factor;
            this->_z *= factor;
            return *this;
            }

    template<typename T>
        inline vec3<T>& vec3<T>::operator/=(const T factor)
            {
            assert(factor != 0);
            this->_x /= factor;
            this->_y /= factor;
            this->_z /= factor;
            return *this;
            }

    template<typename T>
        inline typename vec3<T>::norm_t vec3<T>::normal()const
            {
            return sqrt(squar());
            }

    template<typename T>
        inline typename vec3<T>::norm_t vec3<T>::squar()const
            {
            return _x*_x + _y*_y + _z*_z;
            }

    template<typename T>
        inline void vec3<T>::self_unitization()
            {
            *this /= normal();
            }

    template<typename T>
        inline vec3<precision> vec3<T>::ret_unitization()const
            {
            norm_t div = normal();
            return vec3<norm_t>{ (norm_t)this->_x / div,(norm_t)this->_y / div,(norm_t)this->_z / div };
            }

    template<typename T, typename E>
        inline auto dot(const vec3<T>& v1, const vec3<E>& v2) //-> decltype(v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z())
            {// x1 * x2 + y1 * y2 + z1 * z2
            return v1.x() * v2.x() + v1.y() * v2.y() + v1.z() * v2.z();
            }

    template<typename T, typename E>
        inline auto cross(const vec3<T> v1, const vec3<E>& v2)
            {// v1 × v2
            return vec3<decltype(v1[1] * v2[2] - v1[2] * v2[1])>
                (
                v1[1] * v2[2] - v1[2] * v2[1],
                v1[2] * v2[0] - v1[0] * v2[2],
                v1[0] * v2[1] - v1[1] * v2[0]
                );
            }

    template<typename T>
        inline bool vec3<T>::isnull()const
            {
            return *this == vec3<T>();
            }

}    //namespace lvgm

#endif    //LV_VEC3_H
lv_vec3.h

 

/// all vectors are in here

// -----------------------------------------------------
// [author]        lv
// [ time ]        2018.12 ~ 2018.12
// [brief ]        all vectors are in here
// -----------------------------------------------------


#pragma once

#include <iostream>
#include <cmath>
#include <cassert>
#include <lvgm\lv_precision.h>

#include "lv_vec2.h"
#include "lv_vec3.h"
#include "vec_inout.h"

namespace lvgm
{
    template<typename T> class vec2;

    template<typename T> class vec3;

    template<typename T> class vec4;


    typedef vec2<bool> bvec2;

    typedef vec2<char> cvec2;

    typedef vec2<short> svec2;

    typedef vec2<int> ivec2;

    typedef vec2<float> fvec2;

    typedef vec2<double> dvec2;

    typedef vec2<long double> ldvec2;


    typedef vec3<bool> bvec3;

    typedef vec3<char> cvec3;

    typedef vec3<short> svec3;

    typedef vec3<int> ivec3;

    typedef vec3<float> fvec3;

    typedef vec3<double> dvec3;

    typedef vec3<long double> ldvec3;


    typedef vec4<bool> bvec4;

    typedef vec4<char> cvec4;

    typedef vec4<short> svec4;

    typedef vec4<int> ivec4;

    typedef vec4<float> fvec4;

    typedef vec4<double> dvec4;

    typedef vec4<long double> ldvec4;
}
type_vec.h

 

///vec_inout.h

// -----------------------------------------------------
// [author]        lv
// [ time ]        2018.12 ~ 2018.12
// [brief ]        control the iostream of vec
// -----------------------------------------------------


#pragma once


# ifdef    VEC_OUT

    template<typename T>
        std::ostream& operator<<(std::ostream& cout, const lvgm::vec2<T>& v)
            {
            cout << "[ " << v.x() << ", " << v.y() << " ]";
            return cout;
            }

    template<typename T>
        std::ostream& operator<<(std::ostream& cout, const lvgm::vec3<T>& v)
            {
            cout << "[ " << v.x() << ", " << v.y() << ", " << v.z() << " ]";
            return cout;
            }

    template<typename T>
        std::ostream& operator<<(std::ostream& cout, const lvgm::vec4<T>& v)
        {
            cout << "[ " << v.x() << ", " << v.y() << ", " << v.z() << v.w() << " ]";
            return cout;
        }

#endif

# ifdef VEC2_OUT 

    template<typename T>
        std::ostream& operator<<(std::ostream& cout, const lvgm::vec2<T>& v)
            {
            cout << "[ " << v.x() << ", " << v.y() << " ]";
            return cout;
            }

#endif

# ifdef VEC3_OUT 

    template<typename T>
        std::ostream& operator<<(std::ostream& cout, const lvgm::vec3<T>& v)
            {
            cout << "[ " << v.x() << ", " << v.y() << ", " << v.z() << " ]";
            return cout;
            }

#endif

# ifdef VEC4_OUT 

    template<typename T>
        std::ostream& operator<<(std::ostream& cout, const lvgm::vec4<T>& v)
            {
            cout << "[ " << v.x() << ", " << v.y() << ", " << v.z() << v.w() << " ]";
            return cout;
            }

#endif
vec_inout.h

 

若有什麼問題,請於評論區留言或者郵箱(^_^)

 

感謝您的閱讀,生活愉快`

相關文章
相關標籤/搜索