VTK可移动三维坐标轴 vtkMovableAxesWidget

一.需求

实现一个可移动,可旋转的三位坐标轴。

二,步骤

1.继承 vtkAbstractWidget。将鼠标事件传递给 vtkWidgetRepresentation。

2.继承 vtkWidgetRepresentation 。实现控件长什么样子,三个轴,三个圈。怎么交互,操纵轴,操纵圈该怎么动。

三,实现

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,实现轴和圈的交互。以旋转为例。(感谢 此网友的分享 【VTK】可拖动的坐标轴MovableAxesWidget_Beyond欣的博客-CSDN博客

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());
}
  • 4
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

土拨鼠不是老鼠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值