功能需求说明
选用一种高级计算机程序设计语言,编写一个软件,实现列表曲线或曲面的绘制及其刀具加工路径、数控加工程序的生成。软件功能要求:
- 所设计的软件应具有图形化用户界面(GUI);
- 用户在软件界面上可用随机数方式或手工方式输入若干曲线或曲面的数据点,例如起点、终点、列表型值点等,对于曲线,还可设置步长参数;对于曲面,还可设置步长与行距参数;曲线或曲面的类型不限。
- 具有“绘制理想图形”按钮,用户完成数据点与参数输入后,点击该按钮,软件可绘制出理想的曲线或曲面,若该曲线或曲面有特征多边形,则还能通过型值点反算出控制顶点,并绘制出对应的特征多边形;
- 具有“生成加工路径”按钮,点击该按钮,可根据设定的步长与行距参数自动生成加工该曲线或曲面的刀具路径;(清楚起见,绘制理想图形与刀具路径需用不同颜色)
- 具有“生成加工程序”按钮,点击该按钮,可自动生成一个实现该曲线或曲面加工的G代码数控加工程序文件。
开发环境说明
软件的开发环境为 win10 + QT 5.12.0;编程语言为C++;
参考书:计算机辅助几何设计与非均匀有理B样条
代码说明
坐标系设置
由于默认界面框的原点在左上角,并且向下为Y+,向右为x+,所以在画图或者鼠标捕捉时,要将其转化到正常的直角坐标系,并绘制坐标系。
void Palette::paintEvent(QPaintEvent *event)//绘图事件
{
QPainter* painter = new QPainter(this);
painter->setWindow(-width()/2,height()/2,width(),-height()); //设置窗口,坐标原点在屏幕的正中心
//绘制x轴
QPointF startPoint(-295,0);
QPointF endPoint(295,0);
double x1, y1, x2, y2; //箭头的两点坐标
this->calcVertexes(startPoint.x(), startPoint.y(), endPoint.x(), endPoint.y(), x1, y1, x2, y2);//求得箭头两点坐标
painter->drawLine(startPoint, endPoint);//绘制线段
painter->drawLine(endPoint.x(), endPoint.y(), x1, y1);//绘制箭头
painter->drawLine(endPoint.x(), endPoint.y(), x2, y2);//绘制箭头
//绘制Y轴
startPoint.setX(0);
startPoint.setY(-295);
endPoint.setX(0);
endPoint.setY(295);
B样条绘制数学原理
B样条递推定义:
{ N i , 0 ( u ) = { 1 , π 4 i u i ⩽ u < u i + 1 0 , 其 他 N i , k ( u ) = u − u i u i + 2 − u i N i , k − 1 ( u ) + u i + u + 1 u i + k + 1 − u i + 1 N i + 1 , k − 1 ( u ) 规 定 = 0 0 = 0 \left\{\begin{array}{l}{\mathrm{N}_{i, 0}(u)=\left\{\begin{array}{ll}{1,} & {\frac{\pi}{4 i} u_{i} \leqslant u<u_{i}+1} \\ {0,} & {\mathbb{其他}}\end{array}\right.} \\ {\mathrm{N}_{i, k}(u)=\frac{u-u_{i}}{u_{i+2}-u_{i}} \mathrm{N}_{i, k-1}(u)+\frac{u_{i}+u+1}{u_{i+k+1}-u_{i+1}} \mathrm{N}_{i+1, k-1}(u)} \\ {\mathrm{规定}=\frac{0}{0}=0}\end{array}\right. ⎩⎪⎪⎨⎪⎪⎧Ni,0(u)={1,0,4iπui⩽u<ui+1其他Ni,k(u)=ui+2−uiu−uiNi,k−1(u)+ui+k+1−ui+1ui+u+1Ni+1,k−1(u)规定=00=0
齐次B样条的节点矢量:
U = [ 0 , 0 , 0 , 0 , l 1 + l 2 L , l 1 + l 2 + l 3 L , ⋯ , l 1 + l 2 + ⋯ + l s − 2 L , 1 , 1 , 1 , 1 ] \mathbf{U}=\left[0,0,0,0, \frac{l_{1}+l_{2}}{L}, \frac{l_{1}+l_{2}+l_{3}}{L}, \cdots, \frac{l_{1}+l_{2}+\cdots+l_{s-2}}{L}, 1,1,1,1\right] U=[0,0,0,0,Ll1+l2,Ll1+l2+l3,⋯,Ll1+l2+⋯+ls−2,1,1,1,1]
根据数据点反求控制点:
[
b
1
c
1
a
1
a
2
b
2
c
2
⋱
⋱
a
n
−
3
b
n
−
3
c
n
−
3
c
n
−
2
a
n
−
2
b
n
−
2
]
[
d
1
d
2
⋮
d
n
−
3
d
n
−
2
]
=
[
e
1
e
2
⋮
e
n
−
3
e
n
−
2
]
\left[\begin{array}{ccccc}{b_{1}} & {c_{1}} & {} & {a_{1}} \\ {a_{2}} & {b_{2}} & {} & {c_{2}} \\ {} & {\ddots} & {} & {\ddots} & {} & {} \\ {} & {} & {a_{n-3}} & {} & {b_{n-3}} & {c_{n-3}} \\ {c_{n-2}} & {} & {} & {a_{n-2}} & {b_{n-2}}\end{array}\right]\left[\begin{array}{c}{d_{1}} \\ {d_{2}} \\ {\vdots} \\ {d_{n-3}} \\ {d_{n-2}}\end{array}\right]=\left[\begin{array}{c}{e_{1}} \\ {e_{2}} \\ {\vdots} \\ {e_{n-3}} \\ {e_{n-2}}\end{array}\right]
⎣⎢⎢⎢⎢⎡b1a2cn−2c1b2⋱an−3a1c2⋱an−2bn−3bn−2cn−3⎦⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎢⎡d1d2⋮dn−3dn−2⎦⎥⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎢⎡e1e2⋮en−3en−2⎦⎥⎥⎥⎥⎥⎤
其中:
{
a
i
=
(
Δ
i
+
2
)
2
Δ
i
+
Δ
i
+
1
+
Δ
i
+
2
b
i
=
Δ
i
+
2
(
Δ
i
+
Δ
i
+
1
)
Δ
i
+
Δ
i
+
1
+
Δ
i
+
2
+
Δ
i
+
1
(
Δ
1
+
2
+
Δ
i
+
3
)
Δ
i
+
1
+
Δ
i
+
2
+
Δ
i
+
3
,
i
=
1
,
2
,
⋯
,
n
−
2
c
i
=
(
Δ
i
+
1
)
2
Δ
i
+
1
+
Δ
i
+
2
+
Δ
i
+
3
e
i
=
(
Δ
i
+
1
+
Δ
i
+
2
)
q
i
−
1
\left\{\begin{array}{l}{a_{i}=\frac{\left(\Delta_{i+2}\right)^{2}}{\Delta_{i}+\Delta_{i+1}+\Delta_{i+2}}} \\ {b_{i}=\frac{\Delta_{i+2}\left(\Delta_{i}+\Delta_{i+1}\right)}{\Delta_{i}+\Delta_{i+1}+\Delta_{i+2}}+\frac{\Delta_{i+1}\left(\Delta_{1}+2+\Delta_{i+3}\right)}{\Delta_{i+1}+\Delta_{i+2}+\Delta_{i+3}}, \quad i=1,2, \cdots, n-2} \\ {c_{i}=\frac{\left(\Delta_{i+1}\right)^{2}}{\Delta_{i+1}+\Delta_{i+2}+\Delta_{i+3}}} \\ {e_{i}=\left(\Delta_{i+1}+\Delta_{i+2}\right) q_{i-1}}\end{array}\right.
⎩⎪⎪⎪⎨⎪⎪⎪⎧ai=Δi+Δi+1+Δi+2(Δi+2)2bi=Δi+Δi+1+Δi+2Δi+2(Δi+Δi+1)+Δi+1+Δi+2+Δi+3Δi+1(Δ1+2+Δi+3),i=1,2,⋯,n−2ci=Δi+1+Δi+2+Δi+3(Δi+1)2ei=(Δi+1+Δi+2)qi−1
边界条件:抛物线条件
a
1
=
1
−
Δ
3
Δ
4
(
Δ
3
+
Δ
4
)
2
a_{1}=1-\frac{\Delta_{3} \Delta_{4}}{\left(\Delta_{3}+\Delta_{4}\right)^{2}}
a1=1−(Δ3+Δ4)2Δ3Δ4
b
1
=
Δ
3
Δ
3
+
Δ
4
(
Δ
4
Δ
3
+
Δ
4
−
Δ
3
Δ
3
+
Δ
4
+
Δ
5
)
b_{1}=\frac{\Delta_{3}}{\Delta_{3}+\Delta_{4}}\left(\frac{\Delta_{4}}{\Delta_{3}+\Delta_{4}}-\frac{\Delta_{3}}{\Delta_{3}+\Delta_{4}+\Delta_{5}}\right)
b1=Δ3+Δ4Δ3(Δ3+Δ4Δ4−Δ3+Δ4+Δ5Δ3)
c
1
=
(
Δ
3
)
2
(
Δ
3
+
Δ
4
)
(
Δ
3
+
Δ
4
+
Δ
3
)
c_{1}=\frac{\left(\Delta_{3}\right)^{2}}{\left(\Delta_{3}+\Delta_{4}\right)\left(\Delta_{3}+\Delta_{4}+\Delta_{3}\right)}
c1=(Δ3+Δ4)(Δ3+Δ4+Δ3)(Δ3)2
e
1
=
1
3
(
q
0
+
2
q
1
)
e_{1}=\frac{1}{3}\left(q_{0}+2 q_{1}\right)
e1=31(q0+2q1)
a
n
−
1
=
−
(
Δ
n
)
2
(
Δ
n
−
1
+
Δ
n
)
(
Δ
n
−
1
+
Δ
n
−
1
+
Δ
n
)
a_{n-1}=-\frac{\left(\Delta_{n}\right)^{2}}{\left(\Delta_{n-1}+\Delta_{n}\right)\left(\Delta_{n-1}+\Delta_{n-1}+\Delta_{n}\right)}
an−1=−(Δn−1+Δn)(Δn−1+Δn−1+Δn)(Δn)2
b
n
−
1
=
Δ
n
Δ
n
−
1
+
Δ
n
(
Δ
n
Δ
n
−
1
+
Δ
n
−
1
+
Δ
n
Δ
n
−
1
Δ
n
−
1
+
Δ
n
)
b_{n-1}=\frac{\Delta_{n}}{\Delta_{n-1}+\Delta_{n}}\left(\frac{\Delta_{n}}{\Delta_{n-1}+\Delta_{n-1}+\Delta_{n}} \quad \frac{\Delta_{n-1}}{\Delta_{n-1}+\Delta_{n}}\right)
bn−1=Δn−1+ΔnΔn(Δn−1+Δn−1+ΔnΔnΔn−1+ΔnΔn−1)
c
n
−
1
=
Δ
n
−
1
Δ
n
(
Δ
n
−
1
+
Δ
n
)
2
−
1
c_{n-1}=\frac{\Delta_{n-1} \Delta_{n}}{\left(\Delta_{n-1}+\Delta_{n}\right)^{2}}-1
cn−1=(Δn−1+Δn)2Δn−1Δn−1
e
n
−
1
=
−
1
3
(
q
n
+
2
q
n
−
1
)
e_{n-1}=-\frac{1}{3}\left(q_{n}+2 q_{n-1}\right)
en−1=−31(qn+2qn−1)
相关代码如下:
B样条递推定义:
void Palette::generateCurve()//生成曲线,根据B样条定义
{
curvePoints.clear();
int i=3;
for(double u1=0; u1<1; u1+=0.001)
{
QPointF tmp(0,0);
if (u1 > u[i+1])
{
i=i+1;
}
for(int k=0; k<4;k++)
{
QPointF t = ctrlPoints[i-k];
t=t*Nu(i-k,u1,3);
tmp=tmp+t;
}
curvePoints.push_back(tmp);//尾部插入数据tmp
}
}
齐次B样条的节点矢量:
//节点向量设置
//u[0]-u[3]赋值为0
for(int i=0;i<4;i++)
{
palette->u[i]=0;
}
//u[10]-u[13]赋值为1
for(int i=0;i<4;i++)
{
palette->u[i+10]=1;
}
//u[4]-u[9]的值:
palette->u[4]=l[0]/L;
palette->u[5]=(l[0]+l[1])/L;
palette->u[6]=(l[0]+l[1]+l[2])/L;
palette->u[7]=(l[0]+l[1]+l[2]+l[3])/L;
palette->u[8]=(l[0]+l[1]+l[2]+l[3]+l[4])/L;
palette->u[9]=(l[0]+l[1]+l[2]+l[3]+l[4]+l[5])/L;
根据数据点反求控制点以及抛物线条件:
double detal[13];
//对u[0]-u[12]进行u[i+1]-u[i],前后之差放入detal[i]
for(int i=0;i<13;i++)
{
detal[i]=palette->u[i+1]-palette->u[i]; //detl[i]=u[i+1]-u[i]
}
//抛物线条件a[0]->f[0]
double a[8],b[8],c[8],e[8],f[8]; //角标0-8
a[0]=1-(detal[3]*detal[4])/pow((detal[3]+detal[4]),2);
b[0]=(detal[3]/(detal[3]+detal[4]))*(detal[4]/(detal[3]+detal[4])-detal[3]/(detal[3]+detal[4]+detal[5]));
c[0]=(pow((detal[3]),2))/((detal[3]+detal[4])*(detal[3]+detal[4]+detal[5]));
e[0]=(1.0/3)*(palette->typepoints[0].x()+2*palette->typepoints[1].x()); //X轴坐标
f[0]=(1.0/3)*(palette->typepoints[0].y()+2*palette->typepoints[1].y()); //Y轴坐标
//抛物线条件a[7]->f[7]
a[7]=-(pow((detal[9]),2))/((detal[8]+detal[9])*(detal[8]+detal[8]+detal[9]));
b[7]=(detal[9]/(detal[8]+detal[9]))*(detal[9]/(detal[8]+detal[8]+detal[9])-detal[8]/(detal[8]+detal[9]));
c[7]=detal[8]*detal[9]/pow((detal[8]+detal[9]),2)-1;
e[7]=-(1.0/3)*(palette->typepoints[7].x()+2*palette->typepoints[6].x());
f[7]=-(1.0/3)*(palette->typepoints[7].y()+2*palette->typepoints[6].y());
//抛物线条件a[1]->f[1]....a[6]->f[6]
for(int i=1;i<7;i++)
{
a[i]=(pow((detal[i+3]),2))/(detal[i+1]+detal[i+2]+detal[i+3]);
b[i]=detal[i+3]*(detal[i+1]+detal[i+2])/(detal[i+1]+detal[i+2]+detal[i+3])+detal[i+2]*(detal[i+3]+detal[i+4])/(detal[i+2]+detal[i+3]+detal[i+4]);
c[i]=pow((detal[i+2]),2)/(detal[i+2]+detal[i+3]+detal[i+4]);
e[i]=(detal[i+2]+detal[i+3])*palette->typepoints[i].x();
f[i]=(detal[i+2]+detal[i+3])*palette->typepoints[i].y();
}
//8*8矩阵置0
double matrix[8][8];//定义8*8矩阵
for(int i=0;i<8;i++)
{
for(int j=0;j<8;j++)
{
matrix[i][j]=0;
}
}
//对系数矩阵赋值
matrix[0][0]=a[0];
matrix[0][1]=b[0];
matrix[0][2]=c[0];
for(int i=1;i<7;i++)
{
matrix[i][i-1]=a[i];
matrix[i][i]=b[i];
matrix[i][i+1]=c[i];
}
matrix[7][5]=a[7];
matrix[7][6]=b[7];
matrix[7][7]=c[7];
最终效果
[1]: https://blog.csdn.net/qq_32059343/article/details/86408359
[2]: 计算机辅助几何设计与非均匀有理B样条