VTK 可移动三维坐标轴

VTK 可移动三维坐标轴

一. 需求

利用VTK实现一个可移动,可旋转的三维坐标轴。并通过回调获取其位姿。

二. 效果

三. 步骤

  1. 绘制轴和圈
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

发表回复