前言
前面部分着重介绍了线性代数与空间变换的本质,其大部分是线性代数只是与三维空间计算原理的实际结合,其中大致包含:
1、从复数到二维复平面计算。
2、从3x3矩阵到三维旋转的表示。
3、从4x4矩阵到三维空间的旋转、平移、缩放的表示。
掌握以上线性代数只是,基本能够自主开发一套三维空间位姿计算库,用于计算机中的三维显示计算,例如:医学导航、无人机集群姿态控制、虚拟现实、物理引擎等方面。
其中,前面章节缺乏对四元数的介绍,四元数能非常完美的表示三维空间的旋转,并且也能解决万向节锁死的问题。具备计算量小等特点。
这一板块将会介绍空间位姿计算的实际编写(C++),将会从最基本的点、向量到3x3矩阵、四元数、4x4矩阵及转换类的编写到每个类的测试用例的测试来介绍。本库采用右手直角坐标系,矩阵排列和opengl保持一致,其库也将兼容openggl、vtk等常用三维引擎。
我将会将此项目作为开源库共享(qySpace),其隶属于qytk个人库的一部分。在每一博文后,都将附上计算库的下载链接,将采用LGPLv3开源协议。
点与向量:
一、 点:
与VTK、ITK的设计不同,他们的设计使用了模板的方式,具有灵活性好,可变性高的特点,但这样往往使用起来不方便,代码量大、计算复杂。缺点例如:1、长度可变,往往长度大于3的点或者向量是我们不需要使用的,并且叉乘等运算只存在三维空间。2、使用麻烦、运算麻烦,填充每个分量需要单独设置,代码量大。
point的设计将直接使用长度为3的点,代表三维空间的一个点。其构造函数和析构函数如下:
/// constructor, [0.0, 0.0, 0.0] default.
point();
/// construct from another point.
point(const point& pt);
/// move constructor.
point(point&& pt) noexcept;
/// construct from xyz value.
point(const real x, const real y, const real z);
/// construct from pointer, there must be three values.
point(const real* data);
/// construct from vector, only copy data.
point(const vector& vec);
/// destructor
virtual ~point();
构造和析构一目了然,其中第五个构造是直接从三维空间的向量转成点,实际上,向量也可以看成原点到向量终点的连线,这样转换既符合常规思维,也方便使用。
点的计算部分如下:
/// can be modified according to the index, range:[0,2].
real& operator[](std::uint8_t index);
/// only access.
const real& operator[](std::uint8_t index) const;
/// return true if not equal.
bool operator!=(const point& pt) const;
/// return true if equal, all values equal.
bool operator==(const point& pt) const;
/// operator=, from another point.
point& operator=(const point& pt);
/// move operator=.
point& operator=(point&& pt) noexcept;
/// operator=, from vector, only copy data.
point& operator=(const vector& vec);
/// operator+=, point += vector.
point& operator+=(const vector& vec);
/// operator-=, point -= vector.
point& operator-=(const vector& vec);
/// operator*=, point *= d, equivalent to extending along the origin.
point& operator*=(const real d);
/// operator/=, point /= d, equivalent to shortening along the origin.
point& operator/=(const real d);
/// operator+, return *this + vector.
[[nodiscard]] point operator+(const vector& vec) const;
/// operator-, return *this - vector.
[[nodiscard]] point operator-(const vector& vec) const;
/// operator*, return *this * d.
[[nodiscard]] point operator*(const real d) const;
/// operator/, return *this / d.
[[nodiscard]] point operator/(const real d) const;
除上面之外,点还包括打印、获取是否合法(均为实数)、求两点距离、以及设置和获取点的每个分量值等。其点的数据如下:
private:
/// point data.
real m_data[3];
二、向量:
也将不采用vtk、itk的模板方式,与点几乎相同,只是向量的计算部分与点有些差别。
vector的长度为3,代表三维空间的向量,其构造函数和析构函数如下:
/// constructor, [0.0, 0.0, 1.0] default.
vector();
/// construct from another vector.
vector(const vector& vec);
/// move constructor.
vector(vector&& vec) noexcept;
/// construct from xyz value.
vector(const real x, const real y, const real z);
/// construct from pointer, there must be three values.
vector(const real* data);
/// construct from point, only copy data.
vector(const point& pt);
/// construct from double point, from ptFirst to ptSecond, if same, Axis::Z.
vector(const point& ptFirst, const point& ptSecond);
/// destructor.
virtual ~vector();
可以看出,与点的几乎一样,其中左后一个构造是通过两点构造,向量方向从ptFirst指向ptSecond。这里的向量与物理中的有区别,其只包含大小和方向,不包含作用点。在后续对库的补充中,将会加上这样的类似射线、线段、直线的数据结构,并提供相应的计算。
vector的计算部分如下:
/// can be modified according to the index, range:[0,2].
real& operator[](std::uint8_t index);
/// only access.
const real& operator[](std::uint8_t index) const;
/// return true if not equal.
bool operator!=(const vector& vec) const;
/// return true if equal, all values equal.
bool operator==(const vector& vec) const;
/// operator=, from another vector.
vector& operator=(const vector& vec);
/// move operator=.
vector& operator=(vector&& vec) noexcept;
/// operator=, from point, only copy data.
vector& operator=(const point& pt);
/// operator+=, vector + vector.
vector& operator+=(const vector& vec);
/// operator-=, vector - vector.
vector& operator-=(const vector& vec);
/// operator*=, vector *= d, equivalent to extending vector.
vector& operator*=(const real d);
/// operator/=, vector /= d, equivalent to shortening vector.
vector& operator/=(const real d);
/// operator+, return *this + vector.
[[nodiscard]] vector operator+(const vector& vec) const;
/// operator-, return *this - vector.
[[nodiscard]] vector operator-(const vector& vec) const;
/// operator*, return *this * vector.
real operator*(const vector& vec) const;
/// operator*, return *this * d.
[[nodiscard]] vector operator*(const real d) const;
/// operator/, return *this / d.
[[nodiscard]] vector operator/(const real d) const;
其中,operator*(const vecor& vec)是点乘,与下面的dot函数一样。
/// return length of the vector
real length() const;
/// return length and unit vector.
real normalize();
/// returns the unit vector.
[[nodiscard]] vector normalized() const;
/// return *this * vec.
real dot(const vector& vec) const;
/// return *this x vec.
[[nodiscard]] vector cross(const vector& vec) const;
/// return true if parallel.
bool isParallel(const vector& vec, const real errRadians = TOLERANCE) const;
/// return true if vertical.
bool isVertical(const vector& vec, const real errRadians = TOLERANCE) const;
/// return the radians between *this and another vector, adopt radian system.
real radiansTo(const vector& vec) const;
如上面代码,功能分别为:
1、计算向量长度。
2、将向量单位化。
3、返回单位向量(不改变本身)。
4、两向量点乘。
5、两向量叉乘。
6、判断两个向量是否平行。
7、判断两个向量是否垂直。
8、求两向量夹角。
总结:
三维空间点和空间向量非常简单,计算也非常简单,这里不做过多细节介绍,其测试程序也非常简单,不做介绍,在后面空间计算的例子中,将会体现出这两部分的用法。
qySpace下载地址(github):qySpace
qySpace下载地址(csdn):qySpace