在cad中我们要描述图形的顶点、边、线、面、等信息有很多不同的方法,如果我们使用不同的绘图系统,就有不同的方式或特定的API来解决问题,然而选择较多,我们很难找到最合适的工具,另一方面如果只有解决问题的工具,没有统一的方法也无没办法一劳永逸,因此在图形学中, 我们建立了一套描述几何图形信息与各个图形系统无关联的、简单的基于向量和矩阵运算的数学体系,以及如何用该体系解决可视化图形问题的一些方法。
首先我们来看看mxcad可能会用到的一些坐标系:
1. 窗口坐标系:HTML 采用的是此坐标系,左上角为坐标原点,x 轴向右,y 轴向下,坐标值对应像素值, 在CAD中我们一般称为屏幕坐标。
3. 绘图坐标系:就是cad中的绘图坐标系,在mxcad和mxdraw中基于它的坐标系的坐标, 一般称为文档坐标系。
尽管这四个坐标系在原点位置、坐标轴方向、坐标范围上有所区别,但都是直角坐标系,所以它们都满足直角坐标系的特性:不管原点和轴的方向怎么变,用同样的方法绘制几何图形,它们的形状和相对位置都不变。
那么在直角坐标系如何表示一个点和一段线呢?前面的例子包含 x、y 、z三个轴,所以构成了一个绘图的三维空间,但通常我们只需要考虑x、y。因此我们可以用二维向量来表示这个平面上的点和线段,二维向量其实就是一个包含了两个数值的数组,一个是 x 坐标值,一个是y 坐标值。
假设现在这个平面直角坐标系上有一个向量v:
向量v有两个含义,一是可以表示该坐标系下位于 (x, y) 处的一个点;二是可以表示从原点 (0,0) 到坐标 (x,y) 的一根线段。
同样的两个向量一样可以进行数学运算,比如有两个向量,v1和 v2,如果让它们相加,其结果相当于将 v1向量的终点(x1, y1),沿着 v2向量的方向移动一段距离,这段距离等于 v2向量的长度。
这样我们就可以在平面上得到一个新的点(x1 + x2, y1 + y2),一条新的线段[(0, 0), (x1 + x2, y1 + y2)],以及一段折线:[(0, 0), (x1, y1) , (x1 + x2, y1 + y2)],向量的数学运算如下图:
其次,一个向量包含有长度和方向信息。它的长度可以用向量的 x、y 的平方和的平方根来表示,代码如下:
它的方向可以用与 x 轴的夹角来表示,代码如下:
这个推论意味着一个重要的事实:我们可以很简单地构造出一个绘图向量。也就是说,如果我们希望以点 (x0, y0) 为起点,沿着某个方向画一段长度为 length 的线段,我们只需要构造出如下的一个向量就可以了,代码如下:
下面简单说明了一下mxcad提供的一些向量的运算方法,代码如下:
他们的运算比较容易计算,示例代码如下:
如何理解向量的加减:
1.向量相加:将各个向量依次首尾顺次相接,结果为第一个向量的起点指向最后一个向量的终点向量a加向量b,将a和b首尾相连后,由a的起点指向b的终点,就是a+ b,如下图所示:
2.向量相减:将两个向量平移至公共起点O,从减数向量的终点B指向被减向量的终点A为相减结果将向量a和向量b的起点移到左下角的公共起点O,从点B指向点A的向量就是a - b,如下图:
假设现在有两个N 维向量 a 和 b,其中a = [a1, a2, ...an],b = [b1, b2, ...bn],那向量的点乘代码如下:
在 N 维线性空间中,a、b 向量点积的几何含义是a 向量乘以 b 向量在 a 向量上的投影分量,它的物理含义相当于 a 力作用于物体,产生 b 位移所做的功。点积公式如下图所示:
当然点乘还有两种特殊情况:
1. a、b向量平行,那么它们的夹角是0°, 那么a·b=|a|*|b| 用 JavaScript 代码表示如下:
2. a、b向量垂直,那么它们的夹角是90°,那么a·b=0 用 JavaScript 代码表示如下:
叉乘和点乘有两点不同,首先向量叉乘运算的结果不是标量,而是一个向量;其次,两个向量的叉积与两个向量组成的坐标平面垂直,以二维空间为例,向量 a 和 b 的叉积,就相当于向量 a(蓝色带箭头线段)与向量 b 沿垂直方向的投影(红色带箭头线段)的乘积
那如下图所示,二维向量叉积的几何意义就是向量a、b 组成的平行四边形的面积,向量叉乘如下图:
那叉乘在数学上该怎么计算呢?假设,现在有两个三维向量 a(x1, y1, z1) 和 b(x2, y2, z2),那么,a 与 b 的叉积可以表示为一个如下图的行列式:
其中 i、j、k 分别是 x、y、z 轴的单位向量。我们把这个行列式展开,就能得到如下公式:
二维空间中向量叉乘的物理意义就是 a 和 b 的力矩(力矩你可以理解为一个物体在力的作用下,绕着一个轴转动的趋向。
下面是该类常用的一些方法,主要是与向量进行数学运算得到新的点的位置,代码如下:
仿射变换简单来说就是“线性变换 + 平移”,比如对元素设置 CSS 的 transform 属性就是对元素应用仿射变换,而几何图形的仿射变换具有以下 2 个性质:
1、仿射变换前是直线段的,仿射变换后依然是直线段
2、对两条直线段 a 和 b 应用同样的仿射变换,变换前后线段长度比例保持不变
常见的仿射变换形式包括平移、旋转、缩放以及它们的组合,最简单的就是平移,在mxcad中你可以直接理解为McGePoint3d点通过addvec方法加上一个向量McGeVector3d,就是朝该向量所代表的方向上平移向量的距离。
以上我们知道了如何平移一个点,同样我们可以通过线性变换对一个点进行旋转和缩放,那么什么是线性变换呢? 我们通过向量运算的方式, 得到如何旋转和缩放的方式,只是旋转和缩放, 我们选择用矩阵的形式表示,通过矩阵与向量相乘形式的变换就叫做线性变换。
线性变换除了可以满足仿射变换的 2 个性质之外,还有 2 个额外的性质:
1、线性变换不改变坐标原点(因为如果x0、y0等于零,那么x、y 肯定等于 0);
2、线性变换可以叠加,多个线性变换的叠加结果就是将线性变换的矩阵依次相乘,再与原始向量相乘。
McGeMatrix3d 也是齐次矩阵, 可以直接通过McGeMatrix3d 进行各种线性变换,最终再通过向量的`transformBy`方法应用这个仿射变换。
矩阵的乘法其实对应的就是上面讲述的线性变换可以叠加的这一特性,我们希望通过一个一个的矩阵组合形成一个复杂的仿射变换, 本质是通过矩阵一个一个的相乘得到的最终的矩阵,组合形成的复杂的仿射变换,其中两个A、B矩阵相乘, 以A为例, 这个时候A可以选择左乘或者右乘矩阵B,左乘就是`B* A` 右乘就是`A * B`,通过下图可以理解左乘和右乘的区别,首先假设矩阵A,如下图:
设列向量,如下图:
用列向量去右乘矩阵A,相当于对矩阵A中的列向量做线性组合,如下图:
用列向量左乘矩阵A,相当于对矩阵A中的行向量左线性组合,如下图:
根据上述概念扩展到矩阵乘法中的左乘与右乘, 思路是一样的,设置一个矩阵B,如下图:
用矩阵B来左乘矩阵A,如下图:
因此矩阵B左乘矩阵A得到的新矩阵的每一行都是矩阵A的行向量的线性组合,同理,矩阵B右乘矩阵A得到的新矩阵的每一列都是矩阵A的列向量的线性组合
下面列举一些McGeMatrix3d提供的方法:
凸度值就是圆弧的开始点与结束点距离的一半去除以圆弧的开始点与结束点相连这条线段的中点到圆弧圆心的距离。