过控制点的三次NURBS曲线及Eigen库实现

原理详见《曲线曲面的NURBS 造型技术与数控仿真》第三章部分。这里主要用Eigen库将其实现。

主要函数如下:

1、delta函数

double d(const MatrixXd u, const int i, const int k) {
	return u(0, i + k) - u(0, i);
}

2、计算M矩阵函数

MatrixXd calCuM(const MatrixXd u, const int i) {
	Matrix<double, 4, 4> m;
	m.setZero();
	m(0, 0) = pow(d(u, i + 3, 1), 2) / (d(u, i + 2, 2) * d(u, i + 1, 3));
	m(0, 2) = pow(d(u, i + 2, 1), 2) / (d(u, i + 2, 2) * d(u, i + 2, 3));
	m(1, 2) = 3 * d(u, i + 3, 1) * d(u, i + 2, 1) / (d(u, i + 2, 2) * d(u, i + 2, 3));
	m(2, 2) = 3 * pow(d(u, i + 3, 1), 2) / (d(u, i + 2, 2) * d(u, i + 2, 3));
	m(3, 3) = pow(d(u, i + 3, 1), 2) / (d(u, i + 3, 2) * d(u, i + 3, 3));
	m(0, 1) = 1 - m(0, 0) - m(0, 2);
	m(1, 0) = -3.0 * m(0, 0);
	m(1, 1) = 3.0 * m(0, 0) - m(1, 2);
	m(2, 0) = 3.0 * m(0, 0);
	m(2, 1) = -3.0 * m(0, 0) - m(2, 2);
	m(3, 0) = -m(0, 0);
	m(3, 2) = -(m(2, 2) / 3.0 + m(3, 3) + pow(d(u, i + 3, 1), 2) / (d(u, i + 3, 2) * d(u, i + 2, 3)));
	m(3, 1) = m(0, 0) - m(3, 2) - m(3, 3);
	return m;
}

3、计算NURBS样条曲线函数(未考虑权重,可自行添加)

bool calcuNURBS(const MatrixXd &mat, MatrixXd &vs, MatrixXd &ve, const int N, MatrixXd &outMat) {
	MatrixXd U, temp, tempDiff, dU, A, E, tempPnt, ctrlPnt, tempU, d, M, D, T;
	int row = int(mat.rows()), col = int(mat.cols()), stepSize = 3, outIdx=0;
	double tempSum = 0.0, dt=0.0;

	U.setZero(1, row + stepSize + 3);
	dU.setZero(1, row + stepSize + 3);
	A.setZero(row, row);
	E.setZero(row, col);
	temp.setZero(1, row - 1);

	for (int i = 1; i <= row - 1; i++) {
		tempDiff.setZero(1, col);
		tempDiff = mat.block(i, 0, 1, col) - mat.block(i - 1, 0, 1, col);
		temp(0, i - 1) = tempDiff.norm();
	}

	tempSum = temp.sum();

	U.block(0, row + stepSize - 1, 1, stepSize + 1).setOnes();
	for (int i = stepSize + 1; i <= row + stepSize - 2; i++) {
		U(0, i) = U(0, i - 1) + temp(0, i - stepSize - 1) / tempSum;
	}

	if (vs.norm() == 0) {
		vs = mat.block(1, 0, 1, col) - mat.block(0, 0, 1, col);
	}
	vs.normalize();

	if (ve.norm() == 0) {
		ve = mat.block(row-1, 0, 1, col) - mat.block(row-2, 0, 1, col);
	}
	ve.normalize();

	for (int i = stepSize + 1; i <= row + stepSize - 1; i++) {
		dU(0, i - 1) = U(0, i) - U(0, i - 1);
	}

	A(0, 0) = 1;
	A(row - 1, row - 1) = 1;
	E.block(0, 0, 1, col) = mat.block(0, 0, 1, col) + dU(0, 3) / 3 * vs;
	E.block(row - 1, 0, 1, col) = mat.block(row - 1, 0, 1, col) - dU(0, row + 1) / 3 * ve;

	for (int i = 2; i <= row - 1; i++) {
		A(i - 1, i - 2) = dU(0, i + 2) * dU(0, i + 2) / dU.block(0, i, 1, 3).sum();
		A(i - 1, i - 1) = dU(0, i + 2) * (dU(0, i) + dU(0, i + 1)) / dU.block(0, i, 1, 3).sum() + \
			dU(0, i + 1) * (dU(0, i + 2) + dU(0, i + 3)) / dU.block(0, i + 1, 1, 3).sum();
		A(i - 1, i) = dU(0, i + 1) * dU(0, i + 1) / dU.block(0, i + 1, 1, 3).sum();
		E.block(i - 1, 0, 1, col) = (dU(0, i + 1) + dU(0, i + 2)) * mat.block(i - 1, 0, 1, col);
	}

	tempPnt.setZero();
	tempPnt = A.inverse() * E;
	ctrlPnt.setZero(tempPnt.rows() + 2, tempPnt.cols());
	int ctrlPntRow = int(ctrlPnt.rows());
	ctrlPnt.block(0, 0, 1, col) = mat.block(0, 0, 1, col);
	ctrlPnt.block(1, 0, ctrlPntRow - 2, col) = tempPnt;
	ctrlPnt.block(ctrlPntRow - 1, 0, 1, col) = mat.block(row - 1, 0, 1, col);
	
	//cout << "theory point is: " << endl;
	//cout << ctrlPnt << endl;

	T.resize(1, 4);
	outMat.resize(N, col);
	outMat.setZero();
	dt = (ctrlPntRow - 3) / double(N);
	
	for (int i = 0; i < ctrlPntRow - 3; i++) {
		M = calCuM(U, i);
		//cout << i+1 << "th M is: " << endl;
		//cout << M << endl;
		D = ctrlPnt.block(i, 0, 4, col);
		//cout << i + 1 << "th D is: " << endl;
		//cout << D << endl;
		for (double t = 0.0; t < 1.0; t = t + dt) {
			for (int k = 0; k <= 3; k++) {
				T(0, k) = pow(t, k);
			}
			outMat.block(outIdx, 0, 1, col) = T * M * D;
			outIdx++;
			if (outIdx >= N-1) {
				break;
			}
		}
	}
	outMat.block(outIdx, 0, 1, col) = ctrlPnt.block(ctrlPntRow - 1, 0, 1, col);  // 最后一点
	return true;
}

4、调用示例

int main()
{
	string srcPath = "./srcdata.txt";
	string filePath = "./data.txt";
	Matrix<double, 6, 3> srcMat;
	MatrixXd outMat, vs, ve;
	vs.setZero(); ve.setZero();
    srcMat << 0, 0, 0, 1, 2, 2, 4, 2, 1, 5, 6, 3, 6, 2, -1, 7, 5, 0;
	calcuNURBS(srcMat, vs, ve, 1000, outMat);

	writeDataIntoFile(srcMat, srcPath);
	writeDataIntoFile(outMat, filePath);

	return 0;
}

5、matlab绘图

clc
clear 
close all

srcPnt = textread('srcdata.txt');
nurbsCurve = textread('data.txt');

figure
subplot(221)
plot(srcPnt(:, 1), srcPnt(:, 2), 'bls'); hold on; 
plot(nurbsCurve(:, 1), nurbsCurve(:, 2), 'g-.'); hold on; 
grid on; axis equal
title('x0y');
subplot(222)
plot(srcPnt(:, 1), srcPnt(:, 3), 'bls'); hold on; 
plot(nurbsCurve(:, 1), nurbsCurve(:, 3), 'g-.'); hold on; 
grid on; axis equal
title('x0z');
subplot(223)
plot(srcPnt(:, 2), srcPnt(:, 3), 'bls'); hold on; 
plot(nurbsCurve(:, 2), nurbsCurve(:, 3), 'g-.'); hold on; 
grid on; axis equal
title('y0z');
subplot(224)
plot3(srcPnt(:, 1), srcPnt(:, 2), srcPnt(:, 3), 'bls'); hold on; 
plot3(nurbsCurve(:, 1), nurbsCurve(:, 2), nurbsCurve(:, 3), 'g-.'); hold on; 
grid on; axis equal
title('xyz');  

绘制图形如下:

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值