VTKActor设定旋转中心鼠标移动进行旋转(优化+解决BUG)

梳理之前的思路

将鼠标在Display上的移动分为X和Y两个delta,然后初始化一个基于VTKActor上的点但是与世界坐标系平行的两个个轴用来进行之后的旋转,因为假如鼠标是横向移动,无论Actor是何种位姿,具体的Actor的旋转表现就是绕着Display的纵方向旋转,所以需要保存当前位姿的Actor相较于Display的横纵方向的两个轴,这两个轴的坐标是相对于Actor的局部坐标的,因为我们始终是让Actor进行旋转而不是Camera。

理清楚这一点后,我们需要让Actor上的一点先绕着Y轴(也可以是X轴,但这个是上面保存的那个轴),进行旋转,获得到此次旋转的旋转矩阵,对此次绕着的那个轴去乘上这个旋转矩阵的逆矩阵来获取下一次应该绕的轴。然后让对这次得到的旋转矩阵分解成欧拉角来让vtkTransform进行变换。

之后对X轴进行同样的操作。

这种方式呢会有一个问题,就是如果鼠标斜着移动,那么实际的旋转轴并不是简单的分解到X轴和Y轴就行了,同时将旋转矩阵分解为欧拉角会又一定误差,多次移动后就会导致移动方向紊乱,出现累计误差。

新的思路

新的思路在总体上来说没有大的变化,主要的改动是,不在对旋转轴进行分解,而是直接求出实际的旋转轴,然后绕着这个轴进行旋转,同时vtkTransform的变换不再使用RotateX,RotateY,RotateZ这一系列函数,而是直接使用Concatenate,这个函数可以直接传旋转矩阵进去来进行变换,减少了分解旋转矩阵的资源调用和误差。

具体代码

if ((dx != 0 || dy != 0))
{
	double delta = pow((dx * dx + dy * dy), 0.5) * 0.1;
	cv::Point3d OutPoint = cv::Point3d(0, 0, 0);
	std::vector<double> baseAxis = { //鼠标移动产生的向量
		dx * xAxis->at(0) + dy * yAxis->at(0),
		dx * xAxis->at(1) + dy * yAxis->at(1),
		dx * xAxis->at(2) + dy * yAxis->at(2)
	};
	std::vector<double> zAxis = {	//根据保存的轴叉积得到的Z轴
		(xAxis->at(1) * yAxis->at(2) - xAxis->at(2) * yAxis->at(1)),
		(xAxis->at(2) * yAxis->at(0) - xAxis->at(0) * yAxis->at(2)),
		(xAxis->at(0) * yAxis->at(1) - xAxis->at(1) * yAxis->at(0))
	};
	std::vector<double> rotateAxis = {	//实际的旋转轴
		(zAxis.at(1) * baseAxis.at(2) - zAxis.at(2) * baseAxis.at(1)),
		(zAxis.at(2) * baseAxis.at(0) - zAxis.at(0) * baseAxis.at(2)),
		(zAxis.at(0) * baseAxis.at(1) - zAxis.at(1) * baseAxis.at(0))
	};
	mat = cv::Mat();
	//得到旋转矩阵的函数
	RotateAroundAxis(cv::Point3d(yAxis->at(0), yAxis->at(1), yAxis->at(2)), cv::Point3d(0, 0, 0),
		cv::Vec3d(rotateAxis.at(0), rotateAxis.at(1), rotateAxis.at(2)), delta * (M_PI / 180.0),
		OutPoint, mat);

	mat = mat(cv::Rect(0, 0, 3, 3));
	cv::invert(mat, submatrix);
	cv::Mat matrix1_mat(3, 1, CV_64F);

	matrix1_mat.at<double>(0, 0) = yAxis->at(0);
	matrix1_mat.at<double>(1, 0) = yAxis->at(1);
	matrix1_mat.at<double>(2, 0) = yAxis->at(2);

	cv::Mat result;
	result = submatrix * matrix1_mat;
	// 保存下一次的y轴
	yAxis->at(0) = result.at<double>(0, 0);
	yAxis->at(1) = result.at<double>(1, 0);
	yAxis->at(2) = result.at<double>(2, 0);

	matrix1_mat.at<double>(0, 0) = xAxis->at(0);
	matrix1_mat.at<double>(1, 0) = xAxis->at(1);
	matrix1_mat.at<double>(2, 0) = xAxis->at(2);

	result = submatrix * matrix1_mat;
	// 保存下一次的x轴
	xAxis->at(0) = result.at<double>(0, 0);
	xAxis->at(1) = result.at<double>(1, 0);
	xAxis->at(2) = result.at<double>(2, 0);
}
	rotateAroundAxis(deltX, deltY, &Actor_xAxis, &Actor_yAxis); //上面的那个函数
	vtkSmartPointer<vtkMatrix4x4> AxesMatrix = vtkSmartPointer<vtkMatrix4x4>::New();

	for (int i = 0; i < 3; ++i)
	{
		for (int j = 0; j < 3; ++j)
		{
			AxesMatrix->SetElement(i, j, mat.at<double>(i, j));
		}
	}

	if (axes_actor != nullptr)
	{
		if (!axesTransform)
		{
			axesTransform = vtkSmartPointer<vtkTransform>::New();
			axesTransform->Identity();
		}
		double* axesCenter = axes_actor->GetCenter();
		axesTransform->Translate(axesCenter[0], axesCenter[1], axesCenter[2]);
		axesTransform->Concatenate(AxesMatrix);
		axesTransform->Translate(-axesCenter[0], -axesCenter[1], -axesCenter[2]);
		axes_actor->SetUserTransform(axesTransform);
	}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值