<泛> C++3D数学库设计详解 向量篇
// 注:本内容为作者原创,禁止在其他网站复述内容以及用于商业盈利,如需引用,请标明出处:http://www.cnblogs.com/lv_anchoret/
Preface
为了支持光线追踪的学习,决定写一个3D泛型数学库。
我采用的是windows平台以及C++Template技术
我的库文件组织目录如下
--lvgm
----test
------testVec.cpp
----type_vec
------lv_vec2.h
------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{ ,-, } and intV2{ , }, the value of which as follows [ , -, ] [ , , ] there is a ivec2 : _2ivec{,}, and a integer to construct a ivec3 as follows the vec2 in front of the integer of : [ , , ] the number of in front of vec2: [ , , ] ******* fvec3 test ********** there is a fvec3 as fV{ .f,2.1f, }, the value of which as follows [ , 2.1, ] there is a fvec2 : t{1.2f,}, and a value to construct a ivec3 as follows f2to3 : [ 1.2, , ] △--******************* FUNCTIONS TEST ******************** there is a ivec3{, -, }
the operator + or - of ivec3 as follows: + : [ , -, ]
- :[ -, , - ] ----------------------------------------------------------- there is a ivec3{, -, } ++ivec3: the val of expression:[ , -, ] the val of ivec3:[ , -, ] ivec3++: the val of expression:[ , -, ] the val of ivec3:[ , -, ] the operator of -- is the same as above ----------------------------------------------------------- the operator[] of ivec3 as follows: the intV[] is
----------------------------------------------------------- there are two ivec3s as intV{ ,-, } and intV2{ , }, the value of which as follows intV is not equ to intV2 the operator = such that: intV2 = intV; the result as follows:
intV2 is [ , -, ]
intV is equ to intV2 there are two ivec3s as intV{ ,-, } and intV2{ , }, the value of which as follows the operator += such that: intV += intV2, the result of which as follows: intV is: [ , -, ] the operator -= such that: intV -= intV2, the result of which as follows: intV is: [ , -, ] the value of intV is to become the original value there are two ivec3s as intV{ ,-, } and intV2{ ,, }, the value of which as follows the operator *= such that: intV *= intV2, the result of which as follows: intV is: [ , -, ] the operator /= such that: intV /= intV2, the result of which as follows: intV is: [ , -, ] the value of intV is to become the original value ----------------------------------------------------------- the operator *= (number)such that: intV *= , the result of which as follows: intV is: [ , -, ] the operator /= (number) such that: intV /= , the result of which as follows: intV is: [ , -, ] 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{,-,}, 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{,-,}, there is a float: 3.14, and the result of ivec3*3.14 as follows: res2 is: [ , -, ] 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{,-,} 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{, , } the unitization of intV is: [ , 0.8, 0.6 ] ----------------------------------------------------------- there is a ivec3: intV{,-,}, 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{ ,-, }, intV2{ , }, null;
//null.self_unitization();
ivec3 b;
ivec2 _2ivec{ , };
fvec3 fV{ .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, };
stds cout << "the vec2 in front of the integer of 7: " << _2to3 << enter;
_2to3 = ivec3{ , _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, };
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[] << 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 = { , };
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 = { ,, };
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 *= ;
stds cout << "intV is: " << intV << enter;
stds cout << "the operator /= (number) such that: intV /= 5, the result of which as follows:" << enter;
intV /= ;
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 = { ,-, };
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 = { ,-, };
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 = { ,-, };
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 = { ,, };
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 = { ,-, };
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[] + v2[], v1[] + v2[]);
} 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[] * v2[]);
return vec2<type>((type)v1[] * v2[], (type)v1[] * v2[]);
} 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[] * v2[], v1[] * v2[]);
} 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[] / v2[]);
return vec2<type>((type)v1[] / v2[], (type)v1[] / v2[]);
} 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 != && factor != .);
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 == )return _x;
else if (index == )return _y;
else throw "the index is error";
} template<typename T>
inline T& vec2<T>::operator[](const int index)
{
if (index == )return _x;
else if (index == )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 != );
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 v1[] * v2[] - v1[] * v2[];
} 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[] + v2[], v1[] + v2[], v1[] + v2[]);
} 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[] * v2[]);
return vec3<type>((type)v1[] * v2[], (type)v1[] * v2[], (type)v1[] * v2[]);
} 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[] * v2[], v1[] * v2[], v1[] * v2[]);
} 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[] / v2[]);
return vec3<type>((type)v1[] / v2[], (type)v1[] / v2[], (type)v1[] / v2[]);
} 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 != && factor != .);
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 == )return _x;
else if (index == )return _y;
else if (index == )return _z;
else throw "the index is error";
} template<typename T>
inline T& vec3<T>::operator[](const int index)
{
if (index == )return _x;
else if (index == )return _y;
else if (index == )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 != );
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[] * v2[] - v1[] * v2[])>
(
v1[] * v2[] - v1[] * v2[],
v1[] * v2[] - v1[] * v2[],
v1[] * v2[] - v1[] * v2[]
);
} 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
如有什么问题,请于评论区留言或者邮箱(^_^)
感谢您的阅读,生活愉快`
<泛> C++3D数学库设计详解 向量篇的更多相关文章
- <泛> C++3D数学库设计详解 简单光学几何 && 随机向量生成
// 注:本内容为作者原创,禁止在其他网站复述内容以及用于商业盈利,如需引用,请标明出处:http://www.cnblogs.com/lv_anchoret/ Preface 当初写这个库,是为了 ...
- Dubbo架构设计详解-转
Dubbo架构设计详解 2013-09-03 21:26:59 Yanjun Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解 ...
- Java生鲜电商平台-Java后端生成Token架构与设计详解
Java生鲜电商平台-Java后端生成Token架构与设计详解 目的:Java开源生鲜电商平台-Java后端生成Token目的是为了用于校验客户端,防止重复提交. 技术选型:用开源的JWT架构. 1. ...
- Python爬虫之selenium库使用详解
Python爬虫之selenium库使用详解 本章内容如下: 什么是Selenium selenium基本使用 声明浏览器对象 访问页面 查找元素 多个元素查找 元素交互操作 交互动作 执行JavaS ...
- STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解)
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) 前面 ...
- [转帖]前端-chromeF12 谷歌开发者工具详解 Console篇
前端-chromeF12 谷歌开发者工具详解 Console篇 https://blog.csdn.net/qq_39892932/article/details/82655866 趁着搞 cloud ...
- bt协议详解 DHT篇(上)
bt协议详解 DHT篇(上) 最近开发了一个免费教程的网站,突然产生了仔细了解bt协议的想法,这篇文章是bt协议详解系列的第三篇,后续还会写一些关于搜索和索引的东西,都是在开发这个网站的过程中学习到的 ...
- [转帖]前端-chromeF12 谷歌开发者工具详解 Network篇
前端-chromeF12 谷歌开发者工具详解 Network篇 https://blog.csdn.net/qq_39892932/article/details/82493922 blog 也是原作 ...
- RocketMQ源码详解 | Broker篇 · 其一:线程模型与接收链路
概述 在上一节 RocketMQ源码详解 | Producer篇 · 其二:消息组成.发送链路 中,我们终于将消息发送出了 Producer,在短暂的 tcp 握手后,很快它就会进入目的 Broker ...
随机推荐
- 6个动作4种难度选择!家庭减肥就用hiit
今天推荐一组课程计划,6个动作,后面会教你如何调整课程难度,以便让课程更适合自己的身体情况. 一.深蹲:8-10次 二.俯卧撑:5-8次(女生如果完成不了标准俯卧撑,可以选择跪姿俯卧撑) 三.平板支撑 ...
- IE6下面的css调试工具
在开发过程中,代码部分实现之后,就要着手于前台展示部分的界面,公司的美工又是新手,无奈,只有自己慢慢调了,但IE6之前的版本都没有好的调试工具,后来在网上搜索了一个 IE Developer Tool ...
- 【Hadoop】Win7上搭建Hadoop开发环境,方法一
在Win7上,编写hadoop程序 操作系统:win7 hadoop版本:CDH3u6 1.下载安装JDK,以及Eclipse 2.新建JAVA Project 3.去cloudera网站下载hado ...
- 20145226夏艺华 《Java程序设计》第5周学习总结
教材学习内容总结 第八章 异常处理 语法与继承架构 使用 try.catch Java中所有信息都会被打包为对象,如果愿意,可以尝试(try)捕捉(catch)代表错误的对象后做一些处理 try{ . ...
- CodeForces 714A
Description Today an outstanding event is going to happen in the forest — hedgehog Filya will come t ...
- 【leetcode 简单】 第八十九题 赎金信
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串ransom能不能由第二个字符串magazines里面的字符构成.如果可以构成,返回 true :否则返回 ...
- js 各类判断用户输入字符的格式函数
1.JS 判断IP格式是否正确: function checkIP(ip) { var regular = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;//正则表达式 if (reg ...
- 钉钉头像大小设置 阿里cdn尺寸截取参数设置
默认api的接口返回的avatar字段,是原始图片大小字段,尺寸和空间都是原始大小,如果想节省流量或统一尺寸,可以用阿里cdn自带的尺寸截取功能, 比如钉钉头像 avatar字段 返回值为原始大小ht ...
- 命名实体识别(NER)
一.任务 Named Entity Recognition,简称NER.主要用于提取时间.地点.人物.组织机构名. 二.应用 知识图谱.情感分析.机器翻译.对话问答系统都有应用.比如,需要利用命名实体 ...
- ubuntu更新源列表
1. 备份源列表 sudo cp /etc/apt/sources.list /etc/apt/sources.list_backup 2.修改更新源 打开源列表 sudo gedit /etc/ap ...