【此系列文章基于熔融沉积( fused depostion modeling, FDM )成形工艺】
从这一篇文章开始,我讲一下实体切片方面的一些技术。
切片引擎,实体部分大致包括:
提取边界矢量——>添加多边——>生成填充矢量集合。
其中最难的是生成填充矢量集合,也是整个切片引擎技术的核心,因为衡量一款引擎的好坏的四个核心要素——稳固性;与原始模型的相似度;用了多少材料;打印快慢,都是主要取决于填充矢量的生成技术。目前生成填充矢量的算法还有很多未知的问题有待攻克,对于这一块技术我将在最后与大家讨论,在这一篇文章里,我主要的说一下提取边界矢量的技术。
提取边界矢量,就是在对模型分层的时候,获得模型与某一层(z平面)相交的矢量集合,并且以特定顺序(一般规定顺着Z轴负方向看为正向)首尾相接。
其中难点主要是要所有的层都以特定顺序首尾相接,看下图:
这是某一模型在skeinforge下生成的某一层的矢量集合。看它的边界矢量,就是如上所述,按照某一特定顺序,首尾相接。
这里求三角面片和z平面的交线这是高中解析几何的东西,而首尾相接只需略懂数据结构就非常容易做到的。在这里就不赘述了。
我就只说如何让所有的交线按照某一特定方向来生成边界矢量。
算法步骤如下:
第一步,求出来的三角面片和z平面交线段的两个端点:beginPoint和endPoint,把它假设成为我们想要的符合特定顺序的矢量:phasor。开始节点:beginPoint,结束节点:endPoint。
第二步,就是判断该矢量是否符合我们的要求的,如果不符合就对它做反转。
步骤如下:
1,做beginPoint和endPoint的差vectorDiff。
2,对vectorDiff和该三角面片的法向量normal做叉积cross。
3,beginPoint和cross相加得到vectorAdd。
4,做三个向量(1,1,z),(1,0,z),(0,1,z).这三个向量的第三个元素都是z,要保证线性无关(三个线性无关的向量确定一个平面)。
5,对这三个向量以及vectorAdd做四点行列式,如果行列式的值小于0,反转,否则不反转。
可能对于初学者,四点行列式有些难以理解,对此,请参看我的另一篇博文: Devillers & Guigue算法。
为什么要这样做,有一点点算法功底的同学容易理解,这样做的目的主要是充分利用法向量来判断二维矢量的合理方向,因为对传统的多边形面片离散化的3D模型,法向量唯一标识3D模型面的方向,要使得提取的边界矢量方向规范就必须充分利用法向量信息。
至于我所做的三个向量,是为了标定z平面,只需找到这个平面三个不相关的向量就可以了。
讲这么多,上述算法应该就不难理解了。
下面呈上该算法的代码。
//矢量 struct Phasor { float3 beginPoint,endPoint; int status; int material; int tri_index; void reversal() { float3 temp; memcpy(temp,beginPoint,sizeof(float)*3); memcpy(beginPoint,endPoint,sizeof(float)*3); memcpy(endPoint,temp,sizeof(float)*3); } void copy(Phasor *p) { memcpy(beginPoint,p->beginPoint,sizeof(float)*3); memcpy(endPoint,p->endPoint,sizeof(float)*3); status=p->status; material=p->material; tri_index=p->tri_index; } }; void get_vector_diff( float3& aimV, const float3 a, const float3 b ) { aimV[0] = b[0] - a[0]; aimV[1] = b[1] - a[1]; aimV[2] = b[2] - a[2]; } void cross_product(float3 &result,float3 a, float3 b) { result[0] = a[1]*b[2] - a[2]*b[1]; result[1] = a[2]*b[0] - a[0]*b[2]; result[2] = a[0]*b[1] - a[1]*b[0]; } void get_vector_sum( float3& aimV, const float3 a, const float3 b ) { aimV[0] = a[0] + b[0]; aimV[1] = a[1] + b[1]; aimV[2] = a[2] + b[2]; } //获得四点的行列式 float get_vector4_det( float3 v1, float3 v2, float3 v3, float3 v4 ) { float a[3][3]; for ( int i = 0; i != 3; ++i ) { a[0][i] = v1[i] - v4[i]; a[1][i] = v2[i] - v4[i]; a[2][i] = v3[i] - v4[i]; } return a[0][0] * a[1][1] * a[2][2] + a[0][1] * a[1][2] * a[2][0] + a[0][2] * a[1][0] * a[2][1] - a[0][2] * a[1][1] * a[2][0] - a[0][1] * a[1][0] * a[2][2] - a[0][0] * a[1][2] * a[2][1]; } /// <summary> /// 如果边界矢量不符合要求,改变矢量方向 /// </summary> /// <param name="phasor">矢量</param> /// <param name="normal">法向</param> /// <param name="z">z坐标</param> void STLDelamination::rectifyDirection(Phasor *phasor,float3 normal,float z) { float3 cross; float3 vectorDiff; float3 vectorAdd; float3 a,b,c,temp; a[0]=1; a[1]=1; a[2]=z; b[0]=1; b[1]=0; b[2]=z; c[0]=0; c[1]=1; c[2]=z; get_vector_diff(vectorDiff,phasor->beginPoint,phasor->endPoint); cross_product(cross,normal,vectorDiff); get_vector_sum(vectorAdd,phasor->beginPoint,cross); if(get_vector4_det(a, b, c, vectorAdd )<0) { memcpy(temp,phasor->beginPoint,sizeof(float)*3); memcpy(phasor->beginPoint,phasor->endPoint,sizeof(float)*3); memcpy(phasor->endPoint,temp,sizeof(float)*3); } }
原文地址:http://blog.csdn.net/fourierfeng/article/details/44004459