5、VTK刚体变换

cpp 复制代码
#include <vtkSmartPointer.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkPolyData.h>
#include <vtkMath.h>
#include <vtkCylinderSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkAxesActor.h>
#include <vtkCamera.h>

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);

bool isValidDirection(const double vec[3]) {
    return (vec[0] != 0.0 || vec[1] != 0.0 || vec[2] != 0.0);
}

// 修正后的变换计算:从 (point1, vec1) 到 (point2, vec2)
vtkSmartPointer<vtkTransform> computeRigidTransform(double point1[3], double vec1[3],
                                                    double point2[3], double vec2[3]) {
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();

    if (!isValidDirection(vec1) || !isValidDirection(vec2)) {
        // 无效方向时只平移
        transform->Translate(point2[0] - point1[0], point2[1] - point1[1], point2[2] - point1[2]);
        return transform;
    }

    double v1[3] = {vec1[0], vec1[1], vec1[2]};
    double v2[3] = {vec2[0], vec2[1], vec2[2]};
    vtkMath::Normalize(v1);
    vtkMath::Normalize(v2);

    double axis[3];
    double dot = vtkMath::Dot(v1, v2);
    double angleRad = acos(dot);
    double angleDeg = vtkMath::DegreesFromRadians(angleRad);
    double eps = 1e-6;

    if (fabs(angleRad) < eps) {
        // 方向相同,无需旋转
        axis[0] = axis[1] = axis[2] = 0;
        angleDeg = 0.0;
    } else if (fabs(angleRad - vtkMath::Pi()) < eps) {
        // 方向相反,找一个垂直于 v1 的轴
        if (fabs(v1[0]) < eps) {
            axis[0] = 1; axis[1] = 0; axis[2] = 0;
        } else {
            axis[0] = -v1[1]; axis[1] = v1[0]; axis[2] = 0;
            vtkMath::Normalize(axis);
        }
        angleDeg = 180.0;
    } else {
        vtkMath::Cross(v1, v2, axis);
        vtkMath::Normalize(axis);
    }

    // 正确的变换顺序(后乘规则):
    // 1. 平移到原点  2. 旋转  3. 平移到目标点
    transform->Translate(point2[0], point2[1], point2[2]);
    transform->RotateWXYZ(angleDeg, axis[0], axis[1], axis[2]);
    transform->Translate(-point1[0], -point1[1], -point1[2]);

    return transform;
}

int main() {
    const double height = 2.0;

    // 创建一个圆柱源(默认:中心在原点,沿 Y 轴,范围 -1 到 1)
    auto cylinder = vtkSmartPointer<vtkCylinderSource>::New();
    cylinder->SetHeight(height);
    cylinder->SetRadius(0.1);
    cylinder->SetCenter(0, 0, 0);   // 中心在原点,则底端在 (0, -height/2, 0),顶端在 (0, height/2, 0)

    // 定义三个位姿
    // 默认位姿(圆柱原始状态):底端在 (0, -1, 0),方向 (0,1,0)
    double defaultPoint[3] = {0, -height/2, 0};
    double defaultVec[3]  = {0, 1, 0};

    // 中间位姿 (point1, vec1)
    double point1[3] = {0, height/2, 0};   // 底端在 (0,1,0)
    double vec1[3]   = {1, 0, 0};          // 方向沿 X 轴

    // 最终位姿 (point2, vec2)
    double point2[3] = {2, 2, 2};
    double vec2[3]   = {1, 1, 1};

    // ---- 1. 默认圆柱(灰色) ----
    auto mapperDefault = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapperDefault->SetInputConnection(cylinder->GetOutputPort());
    auto actorDefault = vtkSmartPointer<vtkActor>::New();
    actorDefault->SetMapper(mapperDefault);
    actorDefault->GetProperty()->SetColor(0.5, 0.5, 0.5);
    actorDefault->GetProperty()->SetOpacity(0.5);

    // ---- 2. 从默认变换到中间位姿(青色半透明) ----
    auto transformToMid = computeRigidTransform(defaultPoint, defaultVec, point1, vec1);
    auto filterMid = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
    filterMid->SetInputConnection(cylinder->GetOutputPort());
    filterMid->SetTransform(transformToMid);
    filterMid->Update();
    auto mapperMid = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapperMid->SetInputConnection(filterMid->GetOutputPort());
    auto actorMid = vtkSmartPointer<vtkActor>::New();
    actorMid->SetMapper(mapperMid);
    actorMid->GetProperty()->SetColor(0, 1, 1);
    actorMid->GetProperty()->SetOpacity(0.3);

    // ---- 3. 从中间位姿变换到最终位姿(蓝色实体) ----
    auto transformToFinal = computeRigidTransform(point1, vec1, point2, vec2);
    transformToFinal->Concatenate(transformToMid);

    auto filterFinal = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
    filterFinal->SetInputConnection(cylinder->GetOutputPort());
    //filterFinal->SetInputConnection(filterMid->GetOutputPort());
    filterFinal->SetTransform(transformToFinal);
    filterFinal->Update();

    auto mapperFinal = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapperFinal->SetInputConnection(filterFinal->GetOutputPort());

    auto actorFinal = vtkSmartPointer<vtkActor>::New();
    actorFinal->SetMapper(mapperFinal);
    actorFinal->GetProperty()->SetColor(0, 0, 1);

    // 坐标轴辅助观察
    auto axes = vtkSmartPointer<vtkAxesActor>::New();
    axes->SetTotalLength(6, 6, 6);

    auto renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->AddActor(actorDefault);
    renderer->AddActor(actorMid);
    renderer->AddActor(actorFinal);
    renderer->AddActor(axes);
    renderer->SetBackground(0.1, 0.2, 0.3);

    auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(renderer);
    renderWindow->SetSize(800, 600);

    renderer->GetActiveCamera()->SetFocalPoint(0, 0, 0);
    renderer->GetActiveCamera()->SetPosition(10, -1, 30);

    auto interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
    interactor->SetRenderWindow(renderWindow);
    renderWindow->Render();
    interactor->Start();

    return 0;
}
相关推荐
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner1 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz6 天前
QML Hello World 入门示例
qt
xcyxiner9 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner10 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner10 天前
DicomViewer (添加模型类)3
qt
xcyxiner11 天前
DicomViewer (目录调整) 2
qt
xcyxiner11 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能13 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G13 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt