一. 需求
利用VTK实现一个可移动,可旋转的三维坐标轴。并通过回调获取其位姿。
二. 效果
三. 步骤
- 绘制轴和圈
vtkMovableAxesRepresentation::vtkMovableAxesRepresentation()
{
// The initial state
this->InteractionState = vtkMovableAxesRepresentation::Outside;
// Handle size is in pixels for this widget
this->HandleSize = 5.0;
// Control orientation of normals
this->InsideOut = 0;
// Set up the initial properties
this->CreateDefaultProperties();
// Define the point coordinates
double bounds[6];
bounds[0] = -0.5;
bounds[1] = 0.5;
bounds[2] = -0.5;
bounds[3] = 0.5;
bounds[4] = -0.5;
bounds[5] = 0.5;
// Points 8-14 are down by PositionHandles();
this->BoundingBox = vtkBox::New();
this->PlaceWidget(bounds);
//画 圆
this->AxisCircel = new vtkActor* [3];
this->AxisPolygonSource = new vtkRegularPolygonSource* [3];
this->AxisCircleMapper = new vtkPolyDataMapper*[3];
for(auto i=0;i<3;i++){
this->AxisCircel[i]=vtkActor::New();
this->AxisPolygonSource[i] = vtkRegularPolygonSource::New();
this->AxisCircleMapper[i] = vtkPolyDataMapper::New();
this->AxisPolygonSource[i]->SetNumberOfSides(100); //多边形边数
this->AxisPolygonSource[i]->SetRadius(g_circleRadius); //半径
this->AxisPolygonSource[i]->SetCenter(0, 0, 0); //圆心
this->AxisCircleMapper[i]->SetInputConnection(this->AxisPolygonSource[i]->GetOutputPort());
this->AxisCircel[i]->SetMapper(this->AxisCircleMapper[i]);
this->AxisCircel[i]->GetProperty()->SetOpacity(1); //透明度
this->AxisCircel[i]->GetProperty()->SetLineWidth(g_circleLineWidth);
this->AxisCircel[i]->GetProperty()->SetRepresentationToWireframe();//图形不填充,只要边框
this->AxisCircel[i]->GetProperty()->SetColor(g_normalColor[i][0],g_normalColor[i][1],g_normalColor[i][2]); //颜色
vtkNew<vtkMatrix4x4> initMatrix;
this->AxisCircel[i]->SetUserMatrix(initMatrix);
}
//圆形拾取
this->CircelPicker = vtkCellPicker::New();
this->CircelPicker->SetTolerance(0.001);
for(int i=0;i<3;i++){
this->CircelPicker->AddPickList(this->AxisCircel[i]);
}
this->CircelPicker->PickFromListOn();
this->CurrentCircel=nullptr;
//轴
this->HandleAxis = new vtkAssembly* [3];
for (int i=0; i<3; i++)
{
vtkNew<vtkLineSource> lineSource;
vtkNew<vtkPolyDataMapper> lineMapper;
vtkNew<vtkActor> lineActor;
lineMapper->SetInputConnection(lineSource->GetOutputPort());
lineActor->SetMapper(lineMapper);
double point1[3];
double point2[3];
if(i==0){//x轴
point1[0]=-g_axisLength;
point1[1]=0;
point1[2]=0;
point2[0]=g_axisLength;
point2[1]=0;
point2[2]=0;
}else if(i==1){//y轴
point1[0]=0;
point1[1]=-g_axisLength;
point1[2]=0;
point2[0]=0;
point2[1]=g_axisLength;
point2[2]=0;
}else if(i==2){//z轴
point1[0]=0;
point1[1]=0;
point1[2]=-g_axisLength;
point2[0]=0;
point2[1]=0;
point2[2]=g_axisLength;
}
lineSource->SetPoint1(point1);
lineSource->SetPoint2(point2);
lineActor->GetProperty()->SetColor(g_normalColor[i][0],g_normalColor[i][1],g_normalColor[i][2]);
lineActor->GetProperty()->SetLineWidth(g_axisLineWidth);
//箭头
vtkNew<vtkConeSource> coneSource1;
vtkNew<vtkPolyDataMapper> coneMapper1;
vtkNew<vtkActor> coneActor1;
coneSource1->SetHeight( 0.2 );
coneSource1->SetRadius( 0.04 );
coneSource1->SetResolution( 10 );
coneMapper1->SetInputConnection(coneSource1->GetOutputPort());
coneActor1->SetMapper(coneMapper1);
coneActor1->GetProperty()->SetColor(g_normalColor[i][0],g_normalColor[i][1],g_normalColor[i][2]);
coneSource1->SetCenter(point2);
if(i==0){//x轴
}else if(i==1){//y轴
coneActor1->SetOrigin(point2);
coneActor1->RotateZ(90);
}else if(i==2){//z轴
coneActor1->SetOrigin(point2);
coneActor1->RotateY(-90);
}
//
vtkNew<vtkConeSource> coneSource2;
vtkNew<vtkPolyDataMapper> coneMapper2;
vtkNew<vtkActor> coneActor2;
coneSource2->SetHeight( 0.2 );
coneSource2->SetRadius( 0.04 );
coneSource2->SetResolution( 30 );
coneMapper2->SetInputConnection(coneSource2->GetOutputPort());
coneActor2->SetMapper(coneMapper2);
coneActor2->GetProperty()->SetColor(g_normalColor[i][0],g_normalColor[i][1],g_normalColor[i][2]);
coneSource2->SetCenter(point1);
if(i==0){//x轴
coneActor2->SetOrigin(point1);
coneActor2->RotateY(180);
this->AxisPolygonSource[i]->SetNormal(1,0,0);
}else if(i==1){//y轴
coneActor2->SetOrigin(point1);
coneActor2->RotateZ(-90);
this->AxisPolygonSource[i]->SetNormal(0,1,0);
}else if(i==2){//z轴
coneActor2->SetOrigin(point1);
coneActor2->RotateY(90);
this->AxisPolygonSource[i]->SetNormal(0,0,1);
}
this->HandleAxis[i] = vtkAssembly::New();
this->HandleAxis[i]->AddPart(lineActor);
this->HandleAxis[i]->AddPart(coneActor1);
this->HandleAxis[i]->AddPart(coneActor2);
vtkNew<vtkMatrix4x4> initMatrix;
this->HandleAxis[i]->SetUserMatrix(initMatrix);
}
//坐标轴拾取
this->AxisPicker = vtkCellPicker::New();
this->AxisPicker->SetTolerance(0.001);
for (int i=0; i<3; i++)
{
this->AxisPicker->AddPickList(this->HandleAxis[i]);
}
this->AxisPicker->PickFromListOn();
//
// Internal data members for performance
this->Transform = vtkTransform::New();
this->PlanePoints = vtkPoints::New(VTK_DOUBLE);
this->PlanePoints->SetNumberOfPoints(6);
this->PlaneNormals = vtkDoubleArray::New();
this->PlaneNormals->SetNumberOfComponents(3);
this->PlaneNormals->SetNumberOfTuples(6);
this->Matrix = vtkMatrix4x4::New();
}
2. 实现轴和圈的互动,以旋转为例。
void vtkMovableAxesRepresentation::Rotate(int X, int Y, double *p1, double *p2, double *vpn, int singleAxis)
{
for(int i=0;i<3;i++){
vtkMatrix4x4 *origin_matrixCircle = this->AxisCircel[i]->GetUserMatrix();
vtkNew<vtkMatrix4x4> result_matrixCircle;
RotateByMatrix(origin_matrixCircle,p1,p2,singleAxis,result_matrixCircle);
this->AxisCircel[i]->SetUserMatrix(result_matrixCircle);
vtkMatrix4x4 *origin_matrixAxis = this->HandleAxis[i]->GetUserMatrix();
vtkNew<vtkMatrix4x4> result_matrixAxis;
RotateByMatrix(origin_matrixAxis,p1,p2,singleAxis,result_matrixAxis);
this->HandleAxis[i]->SetUserMatrix(result_matrixAxis);
}
this->Modified();
this->BuildRepresentation();
}
void vtkMovableAxesRepresentation::RotateByMatrix(vtkMatrix4x4 *origin_matrix, double *p1, double *p2,int direction,vtkMatrix4x4* result_matrix)
{
// 将鼠标位置移动到自身坐标系下,求两次鼠标位置向量在投影平面的夹角
vtkNew<vtkTransform> trans;
trans->SetMatrix(origin_matrix);
double pos_t1[4] { p1[0], p1[1], p1[2], 1 };
double pos_t2[4] { p2[0], p2[1], p2[2], 1 };
vtkNew<vtkMatrix4x4> posture_inv;
vtkMatrix4x4::Invert(origin_matrix, posture_inv);
auto pos_t = posture_inv->MultiplyDoublePoint(pos_t1);
double v1[3] = { pos_t[0], pos_t[1], pos_t[2] };
pos_t = posture_inv->MultiplyDoublePoint(pos_t2);
double v2[3] = { pos_t[0], pos_t[1], pos_t[2] };
double normal[3];
if(direction==0){
normal[0] = 1;
normal[1] = 0;
normal[2] = 0;
}else if(direction==1){
normal[0] = 0;
normal[1] = 1;
normal[2] = 0;
}else if(direction==2){
normal[0] = 0;
normal[1] = 0;
normal[2] = 1;
}
double projection1[3], projection2[3];
GetPlaneProjection(normal, v1, projection1);
GetPlaneProjection(normal, v2, projection2);
vtkMath::Normalize(projection1);
vtkMath::Normalize(projection2);
double axis[3];
vtkMath::Cross(projection1, projection2, axis);
double radians = acos(vtkMath::Dot(projection1, projection2));
double degrees = vtkMath::DegreesFromRadians(radians);
trans->RotateWXYZ(degrees, axis);
result_matrix->DeepCopy(trans->GetMatrix());
}
3,感谢网友的分享。
https://blog.csdn.net/a15005784320/article/details/122096432